配置路由html
1 新建一個項目, 建立一個app01和stark應用,stark建立一個service包,並在service下建立stark.py。而後註冊apppython
2 仿照site.py的註冊代碼,寫stark.py代碼:git
class ModelStark(object): def __init__(self, model, site): self.model = model self.site = site class StarkSite(object): def __init__(self): self._registry = {} def register(self, model, stark_class=None): if not stark_class: stark_class = ModelStark self._registry[model] = stark_class(model, self) site = StarkSite()
3 stark應用下的app.py代碼:web
from django.apps import AppConfig from django.utils.module_loading import autodiscover_modules class StarkConfig(AppConfig): name = 'stark' def ready(self): autodiscover_modules('stark')
4 app01 下model.py:數據庫
class UserInfo(models.Model): name=models.CharField(max_length=32) age=models.IntegerField() def __str__(self): return self.name class Book(models.Model): title=models.CharField(max_length=32) def __str__(self): return self.title
5 在app01下stark.py的註冊模型:django
from stark.service.stark import site, ModelStark from .models import * site.register(Book) site.register(UserInfo) print("_registry", site._registry)
6 在項目的urls.py寫路由。app
from django.conf.urls import url from django.contrib import admin from stark.service.stark import site urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^stark/', site.urls), ]
7 在service下stark.py寫整套urls路由ide
from django.conf.urls import url from django.shortcuts import HttpResponse,render class ModelStark(object): def __init__(self, model, site): self.model = model self.site = site class StarkSite(object): def __init__(self): self._registry = {} def register(self, model, stark_class=None): if not stark_class: stark_class = ModelStark self._registry[model] = stark_class(model, self) def add(self, request): return HttpResponse("add") def delete(self, request, id): return HttpResponse("delete") def change(self, request, id): return HttpResponse("change") def list_view(self, request): return HttpResponse("list_view") def get_urls2(self): temp = [] # 添加每一個app/model的增刪改查url temp.append(url(r'^add/', self.add)) temp.append(url(r'^(\d+)/delete/', self.delete)) temp.append(url(r'^(\d+)/change/', self.change)) temp.append(url(r'^$', self.list_view)) return temp @property def urls2(self): return self.get_urls2(), None, None def get_urls(self): temp = [] for model, stark_class_obj in self._registry.items(): model_name = model._meta.model_name app_label = model._meta.app_label # 添加路由 # url(r'app01/user/',) temp.append(url(r'^%s/%s/' % (app_label, model_name), self.urls2)) return temp @property def urls(self): return self.get_urls(), None, None site = StarkSite()
此時運行項目,就會有stark開頭的8條路由。可是每一個模型的增刪改查的返回數據同樣,咱們要作到根據不一樣的app和model返回對應的數據,所以要把增刪改查的路由從新劃分。函數
8 在service下stark.py修改urls路由,此時的代碼:佈局
from django.conf.urls import url from django.shortcuts import HttpResponse,render class ModelStark(object): def __init__(self, model, site): self.model = model self.site = site def add(self, request): return HttpResponse("add") def delete(self, request, id): return HttpResponse("delete") def change(self, request, id): return HttpResponse("change") def list_view(self, request): return HttpResponse("list_view") def get_urls2(self): temp = [] # 添加每一個app/model的增刪改查url temp.append(url(r'^add/', self.add)) temp.append(url(r'^(\d+)/delete/', self.delete)) temp.append(url(r'^(\d+)/change/', self.change)) temp.append(url(r'^$', self.list_view)) return temp @property def urls2(self): return self.get_urls2(), None, None class StarkSite(object): def __init__(self): self._registry = {} def register(self, model, stark_class=None): if not stark_class: stark_class = ModelStark self._registry[model] = stark_class(model, self) def get_urls(self): temp = [] for model, stark_class_obj in self._registry.items(): model_name = model._meta.model_name app_label = model._meta.app_label # 添加路由 # url(r'app01/user/',) temp.append(url(r'^%s/%s/' % (app_label, model_name), stark_class_obj.urls2)) return temp @property def urls(self): return self.get_urls(), None, None site = StarkSite()
由於每一個app和模型類的數據不同以及各自定製的顯示方式不同,因此對於增刪改查就要分開對待,所以就把增刪改查放到ModelStark類中,既然四個視圖函數都放到ModelStark中了,把調用他們的get_urls2也放進去,這樣方便調用,其實就是把self和調用對象保持一致。get_urls2都放進去了,urls2也順便放進去吧,正好他們是一套。
把他們放到ModelStark的目的就是根據不一樣的app和model以及他們在註冊時定製的配置類顯示對應的數據和展現方式。下面的增刪改查都會在ModelStark類中進行配置,而且有一個對象會一致被調用:stark_class_obj
假設app01 下stark.py爲Book模型定製一個配置類,Userinfo不配置:
class BookConfig(ModelStark): pass site.register(Book, BookConfig) site.register(UserInfo)
此時的路由算是配置好了,後面再設置反向解析,下面開始配置視圖。
list_display
首先先看下ModelStark類中的self.model
1 向UserIfo表中,填充一些數據。並寫Userinfo配置類:
class UserConfig(ModelStark): list_display = ["name", "age"]
在service/stark.py的ModelStark類中添加代碼:
class ModelStark(object): list_display = [] ..... def list_view(self, request): print(self.model) # UserInfo print(self.list_display) # ["name", "age"] # 獲取userinfo 的數據 data_list = self.model.objects.all() # ["obj1", "obj2",.....] # 定義一個新的數據列表 格式: """ [ ["name", "age"] ["name", "age"] ....... ] """ new_data_list = [] for obj in data_list: # 獲取data_list中的每個對象 temp = [] # 定義一個內層列表,存儲一個對象全部字段的值 for field in self.list_display: # 獲取每個要展現的字段 ["name", "age"] val = getattr(obj, field) # field是字符串,利用反射獲取對象每一個字段的值, temp.append(val) new_data_list.append(temp) return render(request, 'list.html', locals()) ........
添加list.html文件,代碼:
<body> <h3>數據列表</h3> <div class="container"> <div class="row"> <div class="col-md-9"> <table class="table table-bordered table-striped"> <thead></thead> <tbody> {% for data_list in new_data_list %} <tr> {% for data in data_list %} <td>{{ data }}</td> {% endfor %} </tr> {% endfor %} </tbody> </table> </div> </div> </div> </body>
訪問/strak/app01/userinfo,此時頁面就能顯示數據了
2 此時想在每一列的後面放在編輯按鈕。
在app01/strak.py中給添加一個方法,使每一條數據都有一個編輯按鈕。
from django.utils.safestring import mark_safe ........ class UserConfig(ModelStark): def edit(self): user_id = obj.id return mark_safe("<a>編輯</a>") list_display = ["name", "age", edit] ......
在service/stark.py的list_view中修改代碼:
def list_view(self, request): print(self.model) # UserInfo print(self.list_display) # ["name", "age"] # 獲取userinfo 的數據 data_list = self.model.objects.all() # ["obj1", "obj2",.....] # 定義一個新的數據列表 格式: """ [ ["name", "age"] ["name", "age"] ....... ] """ new_data_list = [] for obj in data_list: # 獲取data_list中的每個對象 temp = [] # 定義一個內層列表,存儲一個對象全部字段的值 for field in self.list_display: # 獲取每個要展現的字段 ["name", "age"] if callable(field): # 判斷字段是否可被調用 val = field(self) else: val = getattr(obj, field) # field是字符串,利用反射獲取對象每一個字段的值, temp.append(val) new_data_list.append(temp) return render(request, 'list.html', locals())
此時訪問/strak/app01/userinfo
3 此時每一列的後面都有一個編輯鏈接,可是並不能跳轉到對應編輯頁面,所以修改url,修改app01/strak.py中的edit方法。
def edit(self, obj): user_id = obj.id return mark_safe("<a href='/stark/app01/userinfo/%s/change/'>編輯</a>" % user_id)
edit方法須要一個obj參數來獲取用戶id,在service/stark.py的list_view中給它傳遞,
def list_view(self, request): print(self.model) # UserInfo print(self.list_display) # ["name", "age"] # 獲取userinfo 的數據 data_list = self.model.objects.all() # ["obj1", "obj2",.....] # 定義一個新的數據列表 格式: """ [ ["name", "age"] ["name", "age"] ....... ] """ new_data_list = [] for obj in data_list: # 獲取data_list中的每個對象 temp = [] # 定義一個內層列表,存儲一個對象全部字段的值 for field in self.list_display: # 獲取每個要展現的字段 ["name", "age"] if callable(field): # 判斷字段是否可被調用 val = field(self, obj) # 給自定義方法傳遞參數 else: val = getattr(obj, field) # field是字符串,利用反射獲取對象每一個字段的值, temp.append(val) new_data_list.append(temp) return render(request, 'list.html', locals())
此時訪問/strak/app01/userinfo,發現每個編輯按鈕都能跳到對應的編輯頁面。
4 可是這樣寫url地址並非最完美的,然而這樣也行,爲了更加完美,那就使用反向解析。
修改service/stark.py中get_urls2:
def get_urls2(self): temp = [] # 添加每一個app/model的增刪改查url model_name = self.model._meta.model_name app_label = self.model._meta.app_label temp.append(url(r'^add/', self.add, name="%s_%s_add" % (app_label, model_name))) temp.append(url(r'^(\d+)/delete/', self.delete, name="%s_%s_delete" % (app_label, model_name))) temp.append(url(r'^(\d+)/change/', self.change, name="%s_%s_change" % (app_label, model_name))) temp.append(url(r'^$', self.list_view, name="%s_%s_list" % (app_label, model_name))) return temp
修改app01/strak.py中的edit:
from django.core.urlresolvers import reverse class UserConfig(ModelStark): def edit(self, obj): model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_change" % (app_label, model_name), args=(obj.id,)) return mark_safe("<a href='%s'>編輯</a>" % _url)
此時再訪問/strak/app01/userinfo,發現每個編輯按鈕都能跳到對應的編輯頁面。
5 既然編輯都完成了,那就再添加一個刪除和checkbox,簡直易如反掌。
修改app01/strak.py:
class UserConfig(ModelStark): def edit(self, obj): model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_change" % (app_label, model_name), args=(obj.id,)) return mark_safe("<a href='%s'>編輯</a>" % _url) def deletes(self, obj): model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_delete" % (app_label, model_name), args=(obj.id,)) return mark_safe("<a href='%s'>刪除</a>" % _url) def checkbox(self, obj): return mark_safe("<input type='checkbox'>") list_display = [ checkbox, "name", "age", edit, deletes]
此時訪問/strak/app01/userinfo,頁面效果:
5 可是,若是某個模型類沒有定製本身的配置類,也能展現本身的默認字段,而且也有複選框、編輯和刪除功能。
把app01/strak.py中的edit、delete、checkbox三個方法所有剪切放到service/stark.py的ModelStark類中,而後把list_display改成list_display = ["__str__"]。爲了保證每一個模型字段和checkbox、編輯、刪除的展現順序,定義一個new_list_display方法,動態的獲取全部的展現字段。具體代碼:
class ModelStark(object): list_display = ["__str__"] def __init__(self, model, site): self.model = model self.site = site def edit(self, obj): """編輯按鈕""" model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_change" % (app_label, model_name), args=(obj.id,)) return mark_safe("<a href='%s'>編輯</a>" % _url) def deletes(self, obj): """刪除按鈕""" model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_delete" % (app_label, model_name), args=(obj.id,)) return mark_safe("<a href='%s'>刪除</a>" % _url) def checkbox(self, obj): """複選框""" return mark_safe("<input type='checkbox'>") def add(self, request): return HttpResponse("add") def delete(self, request, id): return HttpResponse("delete") def change(self, request, id): return HttpResponse("change") def new_list_display(self): temp = [] temp.append(ModelStark.checkbox) temp.extend(self.list_display) temp.append(ModelStark.edit) temp.append(ModelStark.deletes) return temp def list_view(self, request): """列表展現頁""" print(self.model) # UserInfo print(self.list_display) # ["name", "age"] # 獲取userinfo 的數據 data_list = self.model.objects.all() # ["obj1", "obj2",.....] # 定義一個新的數據列表 格式: """ [ ["name", "age"] ["name", "age"] ....... ] """ new_data_list = [] for obj in data_list: # 獲取data_list中的每個對象 temp = [] # 定義一個內層列表,存儲一個對象全部字段的值 for field in self.new_list_display(): # 獲取每個要展現的字段 ["name", "age"] if callable(field): # 判斷字段是否可被調用 val = field(self, obj) # 給自定義方法傳遞參數 else: val = getattr(obj, field) # field是字符串,利用反射獲取對象每一個字段的值, temp.append(val) new_data_list.append(temp) return render(request, 'list.html', locals()) ..........
此時訪問/strak/app01/userinfo和/strak/app01/book,都能展現複選框、默認字段、編輯、刪除。
如今表單數據有了,可是表頭尚未,那獲取表頭數據。若是是複選框列,也在表頭發一個複選框;若是是編輯或者刪除,表頭就顯示操做;若是是其餘就顯示字段名稱。
6 修改service/stark.py中checkbox、edit、deletes方法,判斷獲取的是表頭仍是表單
def edit(self, obj=None, header=False): """編輯按鈕""" if header: # 判斷是否是表頭 return "操做" model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_change" % (app_label, model_name), args=(obj.id,)) return mark_safe("<a href='%s'>編輯</a>" % _url) def deletes(self, obj=None, header=False): """刪除按鈕""" if header: # 判斷是否是表頭 return "操做" model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_delete" % (app_label, model_name), args=(obj.id,)) return mark_safe("<a href='%s'>刪除</a>" % _url) def checkbox(self, obj=None, header=False): """複選框""" if header: # 判斷是否是表頭 return mark_safe("<input id='all_select' type='checkbox'>") return mark_safe("<input class='select' type='checkbox'>")
7 修改service/stark.py中view_list方法,添加獲取表頭的代碼;
# 獲取表頭信息 # 定義一個列表,格式:["複選框", name , age, "操做"....] head_list = [] for field in self.new_list_display(): # [checkbox,__str__, name,age,edit,deletes......] if callable(field): val = field(self, header=True) head_list.append(val) else: if field == '__str__': val = self.model._meta.model_name.upper() # 返回模型類的名稱 else: val = self.model._meta.get_field(field).verbose_name # 獲取字段的verbose_name,不存在就返回Model勒種定義的field名稱 head_list.append(val)
此時ModelStark類的代碼:
class ModelStark(object): list_display = ["__str__"] def __init__(self, model, site): self.model = model self.site = site def edit(self, obj=None, header=False): """編輯按鈕""" if header: # 判斷是否是表頭 return "操做" model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_change" % (app_label, model_name), args=(obj.id,)) return mark_safe("<a href='%s'>編輯</a>" % _url) def deletes(self, obj=None, header=False): """刪除按鈕""" if header: # 判斷是否是表頭 return "操做" model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_delete" % (app_label, model_name), args=(obj.id,)) return mark_safe("<a href='%s'>刪除</a>" % _url) def checkbox(self, obj=None, header=False): """複選框""" if header: # 判斷是否是表頭 return mark_safe("<input id='all_select' type='checkbox'>") return mark_safe("<input class='select' type='checkbox'>") def add(self, request): return HttpResponse("add") def delete(self, request, id): return HttpResponse("delete") def change(self, request, id): return HttpResponse("change") def new_list_display(self): temp = [] temp.append(ModelStark.checkbox) temp.extend(self.list_display) temp.append(ModelStark.edit) temp.append(ModelStark.deletes) return temp def list_view(self, request): """列表展現頁""" print(self.model) # UserInfo print(self.list_display) # ["name", "age"] # 獲取userinfo 的數據 data_list = self.model.objects.all() # ["obj1", "obj2",.....] # 獲取表頭信息 # 定義一個列表,格式:["複選框", name , age, "操做"....] head_list = [] for field in self.new_list_display(): # [checkbox,__str__, name,age,edit,deletes......] if callable(field): val = field(self, header=True) head_list.append(val) else: if field == '__str__': val = self.model._meta.model_name.upper() # 返回模型類的名稱 else: val = self.model._meta.get_field(field).verbose_name # 獲取字段的verbose_name,不存在就返回Model勒種定義的field名稱 head_list.append(val) # 獲取表單信息 # 定義一個新的數據列表 格式: """ [ ["name", "age"] ["name", "age"] ....... ] """ new_data_list = [] for obj in data_list: # 獲取data_list中的每個對象 temp = [] # 定義一個內層列表,存儲一個對象全部字段的值 for field in self.new_list_display(): # 獲取每個要展現的字段 ["name", "age"] if callable(field): # 判斷字段是否可被調用 val = field(self, obj) # 給自定義方法傳遞參數 else: val = getattr(obj, field) # field是字符串,利用反射獲取對象每一個字段的值, temp.append(val) new_data_list.append(temp) return render(request, 'list.html', locals()) def get_urls2(self): temp = [] # 添加每一個app/model的增刪改查url model_name = self.model._meta.model_name app_label = self.model._meta.app_label temp.append(url(r'^add/', self.add, name="%s_%s_add" % (app_label, model_name))) temp.append(url(r'^(\d+)/delete/', self.delete, name="%s_%s_delete" % (app_label, model_name))) temp.append(url(r'^(\d+)/change/', self.change, name="%s_%s_change" % (app_label, model_name))) temp.append(url(r'^$', self.list_view, name="%s_%s_list" % (app_label, model_name))) return temp @property def urls2(self): return self.get_urls2(), None, None
8 修改list.html的代碼,並添加複選框的點擊事件:
<body> <h3>數據列表</h3> <div class="container"> <div class="row"> <div class="col-md-9"> <table class="table table-bordered table-striped"> <thead> <tr> {% for head_name in head_list %} <td>{{ head_name }}</td> {% endfor %} </tr> </thead> <tbody> {% for data_list in new_data_list %} <tr class="data-list"> {% for data in data_list %} <td>{{ data }}</td> {% endfor %} </tr> {% endfor %} </tbody> </table> </div> </div> </div> <script> // 全選事件 $("#all_select").click(function () { if ($(this).prop("checked")){ $(".select").prop("checked", true) } else { $(".select").prop("checked", false) } }); // 每列複選框的點擊事件 $(".data-list").find(":checkbox").change(function () { all_len = $(".data-list").length; checked_len = $(".data-list").find(":checked").length; if (checked_len < all_len){ $("#all_select").prop("checked", false) } else{ $("#all_select").prop("checked", true) } }) </script> </body>
此時訪問/strak/app01/userinfo和/strak/app01/book,表頭和表單都有數據了。
list_display_links
首先判斷模型類有沒有配置list_display_links,若是沒有就顯示編輯列,若是指定了可點擊的字段,那就把這個字段變成可點擊的a標籤,再把編輯列去掉。
在ModelStart類中,添加類屬性list_display_links=[],而後修改new_list_display方法,
1 修改list_viwe中獲取表單數據的代碼,ModelStart類的部分代碼:
class ModelStark(object): list_display = ["__str__"] list_display_links = [] ...... def new_list_display(self): temp = [] temp.append(ModelStark.checkbox) temp.extend(self.list_display) if not self.list_display_links: # 判斷是否指定了可點擊的列 temp.append(ModelStark.edit) temp.append(ModelStark.deletes) return temp def list_view(self, request): """列表展現頁""" # print(self.model) # UserInfo # print(self.list_display) # ["name", "age"] # 獲取userinfo 的數據 data_list = self.model.objects.all() # ["obj1", "obj2",.....] # 獲取表頭信息 # 定義一個列表,格式:["複選框", name , age, "操做"....] head_list = [] for field in self.new_list_display(): # [checkbox,__str__, name,age,edit,deletes......] if callable(field): val = field(self, header=True) head_list.append(val) else: if field == '__str__': val = self.model._meta.model_name.upper() # 返回模型類的名稱 else: val = self.model._meta.get_field(field).verbose_name # 獲取字段的verbose_name,不存在就返回Model勒種定義的field名稱 head_list.append(val) # 獲取表單信息 # 定義一個新的數據列表 格式: """ [ ["name", "age"] ["name", "age"] ....... ] """ new_data_list = [] # print(ModelStark.list_display_links) for obj in data_list: # 獲取data_list中的每個對象 temp = [] # 定義一個內層列表,存儲一個對象全部字段的值 for field in self.new_list_display(): # 獲取每個要展現的字段 ["name", "age"] if callable(field): # 判斷字段是否可被調用 val = field(self, obj) # 給自定義方法傳遞參數 else: val = getattr(obj, field) # field是字符串,利用反射獲取對象每一個字段的值, if field in self.list_display_links: # 判斷字段是否在list_display_links中, model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_change" % (app_label, model_name), args=(obj.id,)) val = mark_safe("<a href='%s'>%s</a>" % (_url, val)) temp.append(val) new_data_list.append(temp) return render(request, 'list.html', locals()) ......
2 在app01/strak.py中修改Userinfo的配置類:
class UserConfig(ModelStark): list_display = ["name", "age"] list_display_links = ["name"]
訪問/strak/app01/userinfo,
效果有了,可是下面的代碼在不少地方重複使用:
model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_change" % (app_label, model_name), args=(obj.id,)) val = mark_safe("<a href='%s'>%s</a>" % (_url, val))
3 這些代碼都是在獲取url,所以直接封裝四個獲取url的方法:get_change_url,get_delete_url,get_add_url,get_list_url。
"""獲取編輯的url""" def get_change_url(self, obj): model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_change" % (app_label, model_name), args=(obj.pk,)) return _url """獲取刪除的url""" def get_delete_url(self, obj): model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_delete" % (app_label, model_name), args=(obj.pk,)) return _url """獲取添加的url""" def get_add_url(self): model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_add" % (app_label, model_name)) return _url """獲取列表的url""" def get_list_url(self, obj): model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_list" % (app_label, model_name)) return _url
4 修改edit、deletes、checkbox的內部代碼:
"""編輯按鈕""" def edit(self, obj=None, header=False): if header: # 判斷是否是表頭 return "操做" _url = self.get_change_url(obj) return mark_safe("<a href='%s'>編輯</a>" % _url) """刪除按鈕""" def deletes(self, obj=None, header=False): if header: # 判斷是否是表頭 return "操做" _url = self.get_delete_url(obj) return mark_safe("<a href='%s'>刪除</a>" % _url) """複選框""" def checkbox(self, obj=None, header=False): if header: # 判斷是否是表頭 return mark_safe("<input id='all_select' type='checkbox'>") return mark_safe("<input class='select' type='checkbox'>")
5 修改list_view的獲取list_display_links的字段的部分代碼,list_view的代碼:
"""列表展現頁""" def list_view(self, request): # print(self.model) # UserInfo # print(self.list_display) # ["name", "age"] # 獲取userinfo 的數據 data_list = self.model.objects.all() # ["obj1", "obj2",.....] # 獲取表頭信息 # 定義一個列表,格式:["複選框", name , age, "操做"....] head_list = [] for field in self.new_list_display(): # [checkbox,__str__, name,age,edit,deletes......] if callable(field): val = field(self, header=True) head_list.append(val) else: if field == '__str__': val = self.model._meta.model_name.upper() # 返回模型類的名稱 else: val = self.model._meta.get_field(field).verbose_name # 獲取字段的verbose_name,不存在就返回Model勒種定義的field名稱 head_list.append(val) # 獲取表單信息 # 定義一個新的數據列表 格式: """ [ ["name", "age"] ["name", "age"] ....... ] """ new_data_list = [] # print(ModelStark.list_display_links) for obj in data_list: # 獲取data_list中的每個對象 temp = [] # 定義一個內層列表,存儲一個對象全部字段的值 for field in self.new_list_display(): # 獲取每個要展現的字段 ["name", "age"] if callable(field): # 判斷字段是否可被調用 val = field(self, obj) # 給自定義方法傳遞參數 else: val = getattr(obj, field) # field是字符串,利用反射獲取對象每一個字段的值, if field in self.list_display_links: # 判斷字段是否在list_display_links中, _url = self.get_change_url(obj) val = mark_safe("<a href='%s'>%s</a>" % (_url, val)) temp.append(val) new_data_list.append(temp) return render(request, 'list.html', locals())
6 同時整理下方法的命名,此時ModelStark類的所有代碼:
class ModelStark(object): list_display = ["__str__"] list_display_links = [] def __init__(self, model, site): self.model = model self.site = site """編輯按鈕""" def edit(self, obj=None, header=False): if header: # 判斷是否是表頭 return "操做" _url = self.get_change_url(obj) return mark_safe("<a href='%s'>編輯</a>" % _url) """刪除按鈕""" def deletes(self, obj=None, header=False): if header: # 判斷是否是表頭 return "操做" _url = self.get_delete_url(obj) return mark_safe("<a href='%s'>刪除</a>" % _url) """複選框""" def checkbox(self, obj=None, header=False): if header: # 判斷是否是表頭 return mark_safe("<input id='all_select' type='checkbox'>") return mark_safe("<input class='select' type='checkbox'>") """獲取編輯的url""" def get_change_url(self, obj): model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_change" % (app_label, model_name), args=(obj.pk,)) return _url """獲取刪除的url""" def get_delete_url(self, obj): model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_delete" % (app_label, model_name), args=(obj.pk,)) return _url """獲取添加的url""" def get_add_url(self): model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_add" % (app_label, model_name)) return _url """獲取列表的url""" def get_list_url(self, obj): model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_list" % (app_label, model_name)) return _url def new_list_display(self): temp = [] temp.append(ModelStark.checkbox) temp.extend(self.list_display) if not self.list_display_links: # 判斷是否指定了可點擊的列 temp.append(ModelStark.edit) temp.append(ModelStark.deletes) return temp def add_view(self, request): return HttpResponse("add") def delete_view(self, request, id): return HttpResponse("delete") def change_view(self, request, id): return HttpResponse("change") """列表展現頁""" def list_view(self, request): # print(self.model) # UserInfo # print(self.list_display) # ["name", "age"] # 獲取userinfo 的數據 data_list = self.model.objects.all() # ["obj1", "obj2",.....] # 獲取表頭信息 # 定義一個列表,格式:["複選框", name , age, "操做"....] head_list = [] for field in self.new_list_display(): # [checkbox,__str__, name,age,edit,deletes......] if callable(field): val = field(self, header=True) head_list.append(val) else: if field == '__str__': val = self.model._meta.model_name.upper() # 返回模型類的名稱 else: val = self.model._meta.get_field(field).verbose_name # 獲取字段的verbose_name,不存在就返回Model勒種定義的field名稱 head_list.append(val) # 獲取表單信息 # 定義一個新的數據列表 格式: """ [ ["name", "age"] ["name", "age"] ....... ] """ new_data_list = [] # print(ModelStark.list_display_links) for obj in data_list: # 獲取data_list中的每個對象 temp = [] # 定義一個內層列表,存儲一個對象全部字段的值 for field in self.new_list_display(): # 獲取每個要展現的字段 ["name", "age"] if callable(field): # 判斷字段是否可被調用 val = field(self, obj) # 給自定義方法傳遞參數 else: val = getattr(obj, field) # field是字符串,利用反射獲取對象每一個字段的值, if field in self.list_display_links: # 判斷字段是否在list_display_links中, _url = self.get_change_url(obj) val = mark_safe("<a href='%s'>%s</a>" % (_url, val)) temp.append(val) new_data_list.append(temp) return render(request, 'list.html', locals()) def get_urls2(self): temp = [] # 添加每一個app/model的增刪改查url model_name = self.model._meta.model_name app_label = self.model._meta.app_label temp.append(url(r'^add/', self.add_view, name="%s_%s_add" % (app_label, model_name))) temp.append(url(r'^(\d+)/delete/', self.delete_view, name="%s_%s_delete" % (app_label, model_name))) temp.append(url(r'^(\d+)/change/', self.change_view, name="%s_%s_change" % (app_label, model_name))) temp.append(url(r'^$', self.list_view, name="%s_%s_list" % (app_label, model_name))) return temp @property def urls2(self): return self.get_urls2(), None, None
增長
如今查的頁面已經有了,把增刪改的功能也作了。先作增長的。爲了表單的複雜,把app01的model.py的模型類都刪了,把stark.py裏面的註冊代碼和配置類代碼也刪了。
1 把下面的模型類代碼放到app01的model.py裏面,而後執行遷移。
from django.db import models # Create your models here. class Author(models.Model): nid = models.AutoField(primary_key=True) name=models.CharField( max_length=32) age=models.IntegerField() # 與AuthorDetail創建一對一的關係 authorDetail=models.OneToOneField(to="AuthorDetail",on_delete=models.CASCADE) def __str__(self): return self.name class AuthorDetail(models.Model): nid = models.AutoField(primary_key=True) birthday=models.DateField() telephone=models.BigIntegerField() addr=models.CharField( max_length=64) def __str__(self): return self.telephone class Publish(models.Model): nid = models.AutoField(primary_key=True) name=models.CharField( max_length=32) city=models.CharField( max_length=32) email=models.EmailField() def __str__(self): return self.name class Book(models.Model): nid = models.AutoField(primary_key=True) title = models.CharField( max_length=32) publishDate=models.DateField() price=models.DecimalField(max_digits=5,decimal_places=2) # 與Publish創建一對多的關係,外鍵字段創建在多的一方 publish=models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE) # 與Author表創建多對多的關係,ManyToManyField能夠建在兩個模型中的任意一個,自動建立第三張表 authors=models.ManyToManyField(to='Author',) def __str__(self): return self.title
2 app01的stark.py裏面的代碼:
from stark.service.stark import site, ModelStark from .models import * class BookConfig(ModelStark): list_display = ["title", "price", "publishDate"] site.register(Author) site.register(Publish) site.register(AuthorDetail) site.register(Book,BookConfig)
在list.html裏面添加一個跳轉到添加數據頁面的鏈接或按鈕,而且在list_view裏把添加的url傳到list.html。
3 使用ModelForm來作表單的處理。ModelStark類中的add_view方法:
def add_view(self, request): class ModelFormDemo(ModelForm): class Meta: model = self.model fields = "__all__" form_obj = ModelFormDemo() return render(request, 'add_view.html', locals())
4 添加add_view.html文件,代碼:
<style> input,select { display: block; width: 100%; height: 34px; padding: 6px 12px; font-size: 14px; line-height: 1.42857143; color: #555; background-color: #fff; background-image: none; border: 1px solid #ccc; border-radius: 4px; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s; -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; } </style> </head> <body> <h3>添加數據</h3> <div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <form action="" method="post" novalidate> {% csrf_token %} {% for field in form_obj %} <div> <label for="">{{ field.label }}</label> {{ field }} <span style="color: red" class=" error pull-right">{{ field.errors.0 }}</span> </div> {% endfor %} <button type="submit" class="btn btn-default pull-right">提交</button> </form> </div> </div> </div> </body>
此時訪問添加頁面,效果
若是想讓字段顯示中文怎麼辦。在add_view的ModelFormDemo裏面加label? 可是咱們並不知道此時訪問的是那張數據表,因此不能寫死。。那怎麼辦?讓用戶本身定義,用戶未定義就用默認的。
5 在ModelStark類中定義一個類屬性:model_class = None。 定義一個獲取用戶定義的ModelFormDemo類的方法。而後修改add_view方法。
class ModelStark(object): list_display = ["__str__"] list_display_links = [] model_class = None ......... # 獲取定義的ModelFormDemo類 def get_modelform_class(self): if not self.model_class: # 若是用戶爲定義,返回默認的ModelFormDemo類名 class ModelFormDemo(ModelForm): class Meta: model = self.model fields = "__all__" return ModelFormDemo else: # 返回用戶定義的ModelFormDemo類名 return self.model_class # 添加視圖 def add_view(self, request): ModelFormDemo = self.get_modelform_class() # 取到的是類名 form_obj = ModelFormDemo() return render(request, 'add_view.html', locals()) .......
6 如今去app01下的stark.py中定製一個ModelForm類:
from django.forms import ModelForm class ModelFormDemo(ModelForm): class Meta: model = Book fields = "__all__" labels = { "title": "書籍名稱", "price": "價格" } class BookConfig(ModelStark): list_display = ["title", "price", "publishDate"] model_class = ModelFormDemo .......
此時去頁面訪問,
OK,如今就作post請求。
7 add_view.py
def add_view(self, request): ModelFormDemo = self.get_modelform_class() # 取到的是類名 if request.method == "POST": form_obj = ModelFormDemo(request.POST) if form_obj.is_valid(): form_obj.save() return redirect(self.get_list_url()) else: return render(request, 'add_view.html', locals()) form_obj = ModelFormDemo() return render(request, 'add_view.html', locals())
如今就能夠去頁面添加數據了。若是進入添加頁面時報錯沒有__str__字段, 在模型類的 __str__方法中將返回值強轉str就行了。
ok添加作好了,接下來編輯。
編輯
添加和編輯使用的表單同樣,所以兩個頁面都導入表單的html代碼。建立form.html。
1 form.html:
<div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <form action="" method="post" novalidate> {% csrf_token %} {% for field in form_obj %} <div> <label for="">{{ field.label }}</label> {{ field }} <span style="color: red" class=" error pull-right">{{ field.errors.0 }}</span> </div> {% endfor %} <button type="submit" class="btn btn-default pull-right">提交</button> </form> </div> </div> </div>
2 add_view.html
<style> input,select { display: block; width: 100%; height: 34px; padding: 6px 12px; font-size: 14px; line-height: 1.42857143; color: #555; background-color: #fff; background-image: none; border: 1px solid #ccc; border-radius: 4px; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s; -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; } </style> </head> <body> <h3>添加數據</h3> {% include 'form.html' %} </body>
3 edit.html
<style> input,select { display: block; width: 100%; height: 34px; padding: 6px 12px; font-size: 14px; line-height: 1.42857143; color: #555; background-color: #fff; background-image: none; border: 1px solid #ccc; border-radius: 4px; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s; -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; } </style> </head> <body> <h3>修改數據</h3> {% include 'form.html' %} </body>
4 ok,頁面完成了,寫編輯的視圖函數。修改change_view方法:
def change_view(self, request, id): ModelFormDemo = self.get_modelform_class() # 取到的是類名 edit_obj = self.model.objects.get(pk=id) if request.method == "POST": form_obj = ModelFormDemo(request.POST, instance=edit_obj) if form_obj.is_valid(): form_obj.save() return redirect(self.get_list_url()) else: return render(request, 'edit_view.html', locals()) form_obj = ModelFormDemo(instance=edit_obj) return render(request, 'edit_view.html', locals())
如今就能夠去頁面修改數據了。修改作好了,接下來刪除。
刪除
1 建立delete_view.html
<body> <form method="post"> {% csrf_token %} <input class="btn btn-danger" type="submit" value="肯定刪除"> <a class="btn btn-warning" href="{{ list_url }}">取消</a> </form> </body>
2 修改delete_view方法
def delete_view(self, request, id): list_url = self.get_list_url() if request.method == "POST": self.model.objects.get(pk=id).delete() return redirect(list_url) return render(request, 'delete_view.html', locals())
增刪改如今算是大功告成。下面繼續查詢,由於admin的查詢姿式有不少,因此若是繼續在list_view方法裏寫代碼會顯得比較亂,所以把查詢封裝在一個方法裏面。
3 定義ShowList類:
class ShowList(object): def __init__(self, config, data_list): self.config = config self.data_list = data_list def show_header(self): # 獲取表頭信息 # 定義一個列表,格式:["複選框", name , age, "操做"....] head_list = [] for field in self.config.new_list_display(): # [checkbox,__str__, name,age,edit,deletes......] if callable(field): val = field(self.config, header=True) head_list.append(val) else: if field == '__str__': val = self.config.model._meta.model_name.upper() # 返回模型類的名稱 else: val = self.config.model._meta.get_field(field).verbose_name # 獲取字段的verbose_name,不存在就返回Model勒種定義的field名稱 head_list.append(val) return head_list def show_body(self): # 獲取表單信息 # 定義一個新的數據列表 格式: """ [ ["name", "age"] ["name", "age"] ....... ] """ new_data_list = [] # print(ModelStark.list_display_links) for obj in self.data_list: # 獲取data_list中的每個對象 temp = [] # 定義一個內層列表,存儲一個對象全部字段的值 for field in self.config.new_list_display(): # 獲取每個要展現的字段 ["name", "age"] if callable(field): # 判斷字段是否可被調用 val = field(self.config, obj) # 給自定義方法傳遞參數 else: val = getattr(obj, field) # field是字符串,利用反射獲取對象每一個字段的值, if field in self.config.list_display_links: # 判斷字段是否在list_display_links中, _url = self.config.get_change_url(obj) val = mark_safe("<a href='%s'>%s</a>" % (_url, val)) temp.append(val) new_data_list.append(temp) return new_data_list
4 修改ModelStark類的list_view,此時ModelStark類的代碼:
class ModelStark(object): list_display = ["__str__"] list_display_links = [] model_class = None def __init__(self, model, site): self.model = model self.site = site """編輯按鈕""" def edit(self, obj=None, header=False): if header: # 判斷是否是表頭 return "操做" _url = self.get_change_url(obj) return mark_safe("<a href='%s'>編輯</a>" % _url) """刪除按鈕""" def deletes(self, obj=None, header=False): if header: # 判斷是否是表頭 return "操做" _url = self.get_delete_url(obj) return mark_safe("<a href='%s'>刪除</a>" % _url) """複選框""" def checkbox(self, obj=None, header=False): if header: # 判斷是否是表頭 return mark_safe("<input id='all_select' type='checkbox'>") return mark_safe("<input class='select' type='checkbox'>") """獲取編輯的url""" def get_change_url(self, obj): model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_change" % (app_label, model_name), args=(obj.pk,)) return _url """獲取刪除的url""" def get_delete_url(self, obj): model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_delete" % (app_label, model_name), args=(obj.pk,)) return _url """獲取添加的url""" def get_add_url(self): model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_add" % (app_label, model_name)) return _url """獲取列表的url""" def get_list_url(self): model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_list" % (app_label, model_name)) return _url # 獲取被指定的全部字段 def new_list_display(self): temp = [] temp.append(ModelStark.checkbox) temp.extend(self.list_display) if not self.list_display_links: # 判斷是否指定了可點擊的列 temp.append(ModelStark.edit) temp.append(ModelStark.deletes) return temp # 獲取定義的ModelFormDemo類 def get_modelform_class(self): if not self.model_class: # 若是用戶爲定義,返回默認的ModelFormDemo類名 class ModelFormDemo(ModelForm): class Meta: model = self.model fields = "__all__" return ModelFormDemo else: # 返回用戶定義的ModelFormDemo類名 return self.model_class # 添加視圖 def add_view(self, request): ModelFormDemo = self.get_modelform_class() # 取到的是類名 if request.method == "POST": form_obj = ModelFormDemo(request.POST) if form_obj.is_valid(): form_obj.save() return redirect(self.get_list_url()) else: return render(request, 'add_view.html', locals()) form_obj = ModelFormDemo() return render(request, 'add_view.html', locals()) def delete_view(self, request, id): list_url = self.get_list_url() if request.method == "POST": self.model.objects.get(pk=id).delete() return redirect(list_url) return render(request, 'delete_view.html', locals()) def change_view(self, request, id): ModelFormDemo = self.get_modelform_class() # 取到的是類名 edit_obj = self.model.objects.get(pk=id) if request.method == "POST": form_obj = ModelFormDemo(request.POST, instance=edit_obj) if form_obj.is_valid(): form_obj.save() return redirect(self.get_list_url()) else: return render(request, 'edit_view.html', locals()) form_obj = ModelFormDemo(instance=edit_obj) return render(request, 'edit_view.html', locals()) """列表展現頁""" def list_view(self, request): # 獲取userinfo 的數據 data_list = self.model.objects.all() # ["obj1", "obj2",.....] # 獲取表頭 show_list = ShowList(self, data_list) head_list = show_list.show_header() # 獲取表體 new_data_list = show_list.show_body() # 獲取添加的url add_url = self.get_add_url() return render(request, 'list.html', locals()) def get_urls2(self): temp = [] # 添加每一個app/model的增刪改查url model_name = self.model._meta.model_name app_label = self.model._meta.app_label temp.append(url(r'^add/', self.add_view, name="%s_%s_add" % (app_label, model_name))) temp.append(url(r'^(\d+)/delete/', self.delete_view, name="%s_%s_delete" % (app_label, model_name))) temp.append(url(r'^(\d+)/change/', self.change_view, name="%s_%s_change" % (app_label, model_name))) temp.append(url(r'^$', self.list_view, name="%s_%s_list" % (app_label, model_name))) return temp @property def urls2(self): return self.get_urls2(), None, None
分頁
1 在stark app下建立一個utils包,而後建立一個page.py,代碼:
class Pagination(object): def __init__(self, current_page, all_count, base_url,params, per_page_num=8, pager_count=11, ): """ 封裝分頁相關數據 :param current_page: 當前頁 :param all_count: 數據庫中的數據總條數 :param per_page_num: 每頁顯示的數據條數 :param base_url: 分頁中顯示的URL前綴 :param pager_count: 最多顯示的頁碼個數 """ try: current_page = int(current_page) except Exception as e: current_page = 1 if current_page < 1: current_page = 1 self.current_page = current_page self.all_count = all_count self.per_page_num = per_page_num self.base_url = base_url # 總頁碼 all_pager, tmp = divmod(all_count, per_page_num) if tmp: all_pager += 1 self.all_pager = all_pager self.pager_count = pager_count # 最多顯示頁碼數 self.pager_count_half = int((pager_count - 1) / 2) import copy params = copy.deepcopy(params) params._mutable = True self.params = params # self.params : {"page":77,"title":"python","nid":1} @property def start(self): return (self.current_page - 1) * self.per_page_num @property def end(self): return self.current_page * self.per_page_num def page_html(self): # 若是總頁碼 < 11個: if self.all_pager <= self.pager_count: pager_start = 1 pager_end = self.all_pager + 1 # 總頁碼 > 11 else: # 當前頁若是<=頁面上最多顯示(11-1)/2個頁碼 if self.current_page <= self.pager_count_half: pager_start = 1 pager_end = self.pager_count + 1 # 當前頁大於5 else: # 頁碼翻到最後 if (self.current_page + self.pager_count_half) > self.all_pager: pager_start = self.all_pager - self.pager_count + 1 pager_end = self.all_pager + 1 else: pager_start = self.current_page - self.pager_count_half pager_end = self.current_page + self.pager_count_half + 1 page_html_list = [] self.params["page"] = 1 first_page = '<li><a href="%s?%s">首頁</a></li>' % (self.base_url, self.params.urlencode(),) page_html_list.append(first_page) if self.current_page <= 1: prev_page = '<li class="disabled"><a href="#">上一頁</a></li>' else: self.params["page"] = self.current_page - 1 prev_page = '<li><a href="%s?%s">上一頁</a></li>' % (self.base_url, self.params.urlencode(),) page_html_list.append(prev_page) for i in range(pager_start, pager_end): self.params["page"] = i if i == self.current_page: temp = '<li class="active"><a href="%s?%s">%s</a></li>' % (self.base_url, self.params.urlencode(), i,) else: temp = '<li><a href="%s?%s">%s</a></li>' % (self.base_url, self.params.urlencode(), i,) page_html_list.append(temp) if self.current_page >= self.all_pager: next_page = '<li class="disabled"><a href="#">下一頁</a></li>' else: self.params["page"] = self.current_page + 1 next_page = '<li><a href="%s?%s">下一頁</a></li>' % (self.base_url, self.params.urlencode(),) page_html_list.append(next_page) self.params["page"] = self.all_pager last_page = '<li><a href="%s?%s">尾頁</a></li>' % (self.base_url, self.params.urlencode(),) page_html_list.append(last_page) return ''.join(page_html_list)
2 在ShowList類中生成分頁對象和每一頁的數據。
class ShowList(object): def __init__(self, config, data_list, request): self.config = config self.data_list = data_list self.request = request # 分頁 data_count = self.data_list.count() # 獲取數據總數量 current_page = self.request.GET.get("page", 1) # 獲取當前頁碼 base_url = self.request.path # 獲取url(不帶參數) # 生成分頁對象 self.paginator = Pagination(current_page, data_count, base_url, self.request.GET, per_page_num=1, pager_count=11) # 當前頁的數據列表 self.page_data = self.data_list[self.paginator.start: self.paginator.end] 。。。。。。。 # list_view傳入request
3 而後修改get_body方法中的代碼:
4 修改list_view.html,插入頁碼列表
<div class="container"> <div class="row"> <div class="col-md-9"> <a href="{{ add_url }}" class="btn btn-primary">添加數據</a> <table class="table table-bordered table-striped"> <thead> <tr> {% for head_name in head_list %} <td>{{ head_name }}</td> {% endfor %} </tr> </thead> <tbody> {% for data_list in new_data_list %} <tr class="data-list"> {% for data in data_list %} <td>{{ data }}</td> {% endfor %} </tr> {% endfor %} </tbody> </table> <nav> <ul class="pagination"> {{ show_list.paginator.page_html|safe }} </ul> </nav> </div> </div> </div>
Search
1 在ModelStark類中添加類屬性search_fields = [],而後添加一個get_search方法,根據search關鍵字進行模糊查詢。
def get_search(self, request): key_word = request.GET.get("q", "") search_connection = Q() if key_word: search_connection.connector = 'or' for field in self.search_fields: search_connection.children.append((field+"__contains", key_word)) return key_word, search_connection
2 修改list_view方法的代碼
def list_view(self, request): # 獲取search的key_word,Q對象 key_word, search_connection = self.get_search(request) # 獲取userinfo 的數據,並進行search過濾 data_list = self.model.objects.all().filter(search_connection) # 獲取表頭 show_list = ShowList(self, data_list, request) head_list = show_list.show_header() # 獲取表體 new_data_list = show_list.show_body() # 獲取添加的url add_url = self.get_add_url() return render(request, 'list.html', locals())
3 修改list_view.html
<div class="container"> <div class="row"> <div class="col-md-9"> <a href="{{ add_url }}" class="btn btn-primary">添加數據</a> <form method="get" class="pull-right"> {% if show_list.config.search_fields %} <input type="text" name="q" value="{{ key_word }}"> <input type="submit" class="btm btn-primary" value="搜索"> {% endif %} </form> <table class="table table-bordered table-striped"> <thead> <tr> {% for head_name in head_list %} <td>{{ head_name }}</td> {% endfor %} </tr> </thead> <tbody> {% for data_list in new_data_list %} <tr class="data-list"> {% for data in data_list %} <td>{{ data }}</td> {% endfor %} </tr> {% endfor %} </tbody> </table> <nav> <ul class="pagination"> {{ show_list.paginator.page_html|safe }} </ul> </nav> </div> </div> </div>
在app01的stark.py中定義了search_fields後,就能根據設定的字段進行search查詢了。
action
1 在ModelStark類中添加類屬性actions = [],在ShowList類中定義get_actions_list方法,獲取用戶定製的全部action操做。
...... class ShowList(object): def __init__(self, config, data_list, request): ........ # actions self.actions = self.config.actions # 獲取action操做 def get_actions_list(self): temp = [] for action in self.actions: temp.append({ "name": action.__name__, "desc": action.short_description }) return temp .......
2 修改ModelStark類中的checkbox方法:
"""複選框""" def checkbox(self, obj=None, header=False): if header: # 判斷是否是表頭 return mark_safe("<input id='all_select' type='checkbox'>") return mark_safe("<input class='select' name='selected_id' type='checkbox' value='%s'>" % obj.pk)
3 修改list_view.html,添加下拉框
<div class="container"> <div class="row"> <div class="col-md-9"> <a href="{{ add_url }}" class="btn btn-primary">添加數據</a> <form method="get" class="pull-right"> {% if show_list.config.search_fields %} <input type="text" name="q" value="{{ key_word }}"> <input type="submit" class="btm btn-primary" value="搜索"> {% endif %} </form> <form method="post"> {% csrf_token %} <select name="action" style="width: 200px;padding: 5px 8px;display: inline-block"> <option>------</option> {% for action in show_list.get_actions_list %} <option value="{{ action.name }}">{{ action.desc }}</option> {% endfor %} </select><button type="submit" class="btn btn-info">Go</button> <table class="table table-bordered table-striped"> <thead> <tr> {% for head_name in head_list %} <td>{{ head_name }}</td> {% endfor %} </tr> </thead> <tbody> {% for data_list in new_data_list %} <tr class="data-list"> {% for data in data_list %} <td>{{ data }}</td> {% endfor %} </tr> {% endfor %} </tbody> </table> </form> <nav> <ul class="pagination"> {{ show_list.paginator.page_html|safe }} </ul> </nav> </div> </div> </div>
4 在app01 stark.py中的BookConfig類中定義一個修改價格的action
class BookConfig(ModelStark): list_display = ["title", "price", "publishDate"] model_class = ModelFormDemo search_fields = ["title", "price"] def edit_price_action(self, request, queryset): queryset.update(price=111) edit_price_action.short_description = "修改價格" actions = [edit_price_action]
5 修改ModelStark類中list_view方法。
def list_view(self, request): if request.method == "POST": action_name = request.POST.get("action") # 獲取執行的action名稱 id_list = request.POST.getlist("selected_id") # 獲取被選中的id action_func = getattr(self, action_name) # 反射獲取函數 queryset = self.model.objects.filter(pk__in=id_list) # 過濾被選中的查詢集 action_func(request, queryset) # 執行action return redirect(self.get_list_url()) 。。。。。。。
ok,如今就能批量的修改書籍價格。
然而admin的action有一個默認的批量刪除,so,下面添加這個功能。
1 在ModelStark類中添加一個delete_action方法
def delete_action(self, request, queryset): queryset.delete() delete_action.short_description = "批量刪除"
2 而後再定義一個new_action方法
def new_actions(self): temp = [] temp.append(ModelStark.delete_action) temp.extend(self.actions) return temp
3 而後修改ShowList的__init__中self.action
self.actions = self.config.new_actions()
如今就能批量刪除了。此時ModelStark類的代碼:
class ModelStark(object): list_display = ["__str__"] list_display_links = [] model_class = None search_fields = [] actions = [] filter_fields = [] def __init__(self, model, site): self.model = model self.site = site # 批量刪除 def delete_action(self, request, queryset): queryset.delete() delete_action.short_description = "批量刪除" """編輯按鈕""" def edit(self, obj=None, header=False): if header: # 判斷是否是表頭 return "操做" _url = self.get_change_url(obj) return mark_safe("<a href='%s'>編輯</a>" % _url) """刪除按鈕""" def deletes(self, obj=None, header=False): if header: # 判斷是否是表頭 return "操做" _url = self.get_delete_url(obj) return mark_safe("<a href='%s'>刪除</a>" % _url) """複選框""" def checkbox(self, obj=None, header=False): if header: # 判斷是否是表頭 return mark_safe("<input id='all_select' type='checkbox'>") return mark_safe("<input class='select' name='selected_id' type='checkbox' value='%s'>" % obj.pk) """獲取編輯的url""" def get_change_url(self, obj): model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_change" % (app_label, model_name), args=(obj.pk,)) return _url """獲取刪除的url""" def get_delete_url(self, obj): model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_delete" % (app_label, model_name), args=(obj.pk,)) return _url """獲取添加的url""" def get_add_url(self): model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_add" % (app_label, model_name)) return _url """獲取列表的url""" def get_list_url(self): model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_list" % (app_label, model_name)) return _url # 獲取全部的action def new_actions(self): temp = [] temp.append(ModelStark.delete_action) temp.extend(self.actions) return temp # 獲取被指定的全部字段 def new_list_display(self): temp = [] temp.append(ModelStark.checkbox) temp.extend(self.list_display) if not self.list_display_links: # 判斷是否指定了可點擊的列 temp.append(ModelStark.edit) temp.append(ModelStark.deletes) return temp # 獲取定義的ModelFormDemo類 def get_modelform_class(self): if not self.model_class: # 若是用戶爲定義,返回默認的ModelFormDemo類名 class ModelFormDemo(ModelForm): class Meta: model = self.model fields = "__all__" return ModelFormDemo else: # 返回用戶定義的ModelFormDemo類名 return self.model_class # 添加視圖 def add_view(self, request): ModelFormDemo = self.get_modelform_class() # 取到的是類名 if request.method == "POST": form_obj = ModelFormDemo(request.POST) if form_obj.is_valid(): form_obj.save() return redirect(self.get_list_url()) else: return render(request, 'add_view.html', locals()) form_obj = ModelFormDemo() print(form_obj) return render(request, 'add_view.html', locals()) # 刪除視圖 def delete_view(self, request, id): list_url = self.get_list_url() if request.method == "POST": self.model.objects.get(pk=id).delete() return redirect(list_url) return render(request, 'delete_view.html', locals()) # 編輯視圖 def change_view(self, request, id): ModelFormDemo = self.get_modelform_class() # 取到的是類名 edit_obj = self.model.objects.get(pk=id) if request.method == "POST": form_obj = ModelFormDemo(request.POST, instance=edit_obj) if form_obj.is_valid(): form_obj.save() return redirect(self.get_list_url()) else: return render(request, 'edit_view.html', locals()) form_obj = ModelFormDemo(instance=edit_obj) return render(request, 'edit_view.html', locals()) # 獲取search關鍵字和search字段 def get_search(self, request): key_word = request.GET.get("q", "") search_connection = Q() if key_word: key_word = key_word.strip() search_connection.connector = 'or' for field in self.search_fields: search_connection.children.append((field+"__contains", key_word)) return key_word, search_connection """列表展現頁""" def list_view(self, request): if request.method == "POST": action_name = request.POST.get("action") # 獲取執行的action名稱 id_list = request.POST.getlist("selected_id") # 獲取被選中的id action_func = getattr(self, action_name) # 反射獲取函數 queryset = self.model.objects.filter(pk__in=id_list) # 過濾被選中的查詢集 action_func(request, queryset) # 執行action return redirect(self.get_list_url()) # 獲取search的key_word,Q對象 key_word, search_connection = self.get_search(request) # 獲取userinfo 的數據,並進行search過濾 data_list = self.model.objects.all().filter(search_connection) # 獲取表頭 show_list = ShowList(self, data_list, request) head_list = show_list.show_header() # 獲取表體 new_data_list = show_list.show_body() # 獲取添加的url add_url = self.get_add_url() return render(request, 'list.html', locals()) def get_urls2(self): temp = [] # 添加每一個app/model的增刪改查url model_name = self.model._meta.model_name app_label = self.model._meta.app_label temp.append(url(r'^add/', self.add_view, name="%s_%s_add" % (app_label, model_name))) temp.append(url(r'^(\d+)/delete/', self.delete_view, name="%s_%s_delete" % (app_label, model_name))) temp.append(url(r'^(\d+)/change/', self.change_view, name="%s_%s_change" % (app_label, model_name))) temp.append(url(r'^$', self.list_view, name="%s_%s_list" % (app_label, model_name))) return temp @property def urls2(self): return self.get_urls2(), None, None
ShowList類的代碼;
class ShowList(object): def __init__(self, config, data_list, request): self.config = config self.data_list = data_list self.request = request # 分頁 data_count = self.data_list.count() # 獲取數據總數量 current_page = int(self.request.GET.get("page", 1)) # 獲取當前頁碼 base_url = self.request.path # 獲取url(不帶參數) # 生成分頁對象 self.paginator = Pagination(current_page, data_count, base_url, self.request.GET, per_page_num=2, pager_count=11) # 當前頁的數據列表 self.page_data = self.data_list[self.paginator.start: self.paginator.end] # actions self.actions = self.config.new_actions() # 獲取action操做 def get_actions_list(self): temp = [] for action in self.actions: temp.append({ "name": action.__name__, "desc": action.short_description }) return temp def show_header(self): # 獲取表頭信息 # 定義一個列表,格式:["複選框", name , age, "操做"....] head_list = [] for field in self.config.new_list_display(): # [checkbox,__str__, name,age,edit,deletes......] if callable(field): val = field(self.config, header=True) head_list.append(val) else: if field == '__str__': val = self.config.model._meta.model_name.upper() # 返回模型類的名稱 else: val = self.config.model._meta.get_field(field).verbose_name # 獲取字段的verbose_name,不存在就返回Model勒種定義的field名稱 head_list.append(val) return head_list def show_body(self): # 獲取表單信息 # 定義一個新的數據列表 格式: """ [ ["name", "age"] ["name", "age"] ....... ] """ new_data_list = [] for obj in self.page_data: # 獲取data_list中的每個對象 temp = [] # 定義一個內層列表,存儲一個對象全部字段的值 for field in self.config.new_list_display(): # 獲取每個要展現的字段 ["name", "age"] if callable(field): # 判斷字段是否可被調用 val = field(self.config, obj) # 給自定義方法傳遞參數 else: val = getattr(obj, field) # field是字符串,利用反射獲取對象每一個字段的值, if field in self.config.list_display_links: # 判斷字段是否在list_display_links中, _url = self.config.get_change_url(obj) val = mark_safe("<a href='%s'>%s</a>" % (_url, val)) temp.append(val) new_data_list.append(temp) return new_data_list
filter_fields
1 在ModelStark類中定義一個類屬性filter_fields=[],而後再ShowList類中定義一個get_filter_linktags方法,代碼:
def get_filter_linktags(self): link_dict = {} # 定義字段對應的a鏈接 {"book":["<a>金平..</a>", "<a>"], ...} for filter_field in self.config.filter_fields: # 獲取要過濾的字段 ["book", "author",..... ] url_params = copy.deepcopy(self.request.GET) # 獲取參數 current_field_id = self.request.GET.get(filter_field, 0) # 獲取當前被選中的字段的id filter_field_obj = self.config.model._meta.get_field(filter_field) # 獲取字段對象 data_list = filter_field_obj.rel.to.objects.all() # 根據字段對象獲取該模型類的queryset對象["book1","book2",...] temp = [] # 定義一個臨時列表 for obj in data_list: url_params[filter_field] = obj.pk _url = url_params.urlencode() if int(current_field_id) == obj.pk: link_tag = "<a href='?%s'>%s</a>" % (_url, str(obj)) else: link_tag = "<a href='?%s'>%s</a>" % (_url, str(obj)) temp.append(link_tag) link_dict[filter_field] = temp return link_dict
2 app01 stark.py的BookConfig類中定義過濾字段
class BookConfig(ModelStark): list_display = ["title", "price", "publishDate"] model_class = ModelFormDemo search_fields = ["title", "price"] def edit_price_action(self, request, queryset): queryset.update(price=111) edit_price_action.short_description = "修改價格" actions = [edit_price_action] filter_fields = ["authors", "publish"] # 先用多對多和一對多的字段
3 修改list_view.html代碼,加一個過濾佈局並傳數據:
<div class="container"> <div class="row"> <div class="col-md-9"> <a href="{{ add_url }}" class="btn btn-primary">添加數據</a> <form method="get" class="pull-right"> {% if show_list.config.search_fields %} <input type="text" name="q" value="{{ key_word }}"> <input type="submit" class="btm btn-primary" value="搜索"> {% endif %} </form> <form method="post"> {% csrf_token %} <select name="action" style="width: 200px;padding: 5px 8px;display: inline-block"> <option>------</option> {% for action in show_list.get_actions_list %} <option value="{{ action.name }}">{{ action.desc }}</option> {% endfor %} </select><button type="submit" class="btn btn-info">Go</button> <table class="table table-bordered table-striped"> <thead> <tr> {% for head_name in head_list %} <td>{{ head_name }}</td> {% endfor %} </tr> </thead> <tbody> {% for data_list in new_data_list %} <tr class="data-list"> {% for data in data_list %} <td>{{ data }}</td> {% endfor %} </tr> {% endfor %} </tbody> </table> </form> <nav> <ul class="pagination"> {{ show_list.paginator.page_html|safe }} </ul> </nav> </div> <div class="col-md-3"> <div class="filter"> <h3>Filter</h3> {% for field, link_tag in show_list.get_filter_linktags.items %} <div class="well"> <p>{{ field|upper }}</p> {% for tag in link_tag %} <p>{{ tag|safe }}</p> {% endfor %} </div> {% endfor %} </div> </div> </div> </div>
此時就能顯示要過濾的全部字段和對應的數據,並且鏈接也拼接無誤。如今改下a標籤的樣式。
4 修改get_filter_linktags方法:
def get_filter_linktags(self): link_dict = {} # 定義字段對應的a鏈接 {"book":["<a>金平..</a>", "<a>"], ...} for filter_field in self.config.filter_fields: # 獲取要過濾的字段 ["book", "author",..... ] url_params = copy.deepcopy(self.request.GET) # 獲取參數 current_field_id = self.request.GET.get(filter_field, 0) # 獲取當前被選中的字段的id filter_field_obj = self.config.model._meta.get_field(filter_field) # 獲取字段對象 data_list = filter_field_obj.rel.to.objects.all() # 根據字段對象獲取該模型類的queryset對象["book1","book2",...] temp = [] # 定義一個臨時列表 for obj in data_list: url_params[filter_field] = obj.pk _url = url_params.urlencode() if int(current_field_id) == obj.pk: link_tag = "<a class='active' href='?%s'>%s</a>" % (_url, str(obj)) else: link_tag = "<a href='?%s'>%s</a>" % (_url, str(obj)) temp.append(link_tag) link_dict[filter_field] = temp return link_dict
5 給list_view.html中的a標籤加樣式
<style> .filter a{ color: #999; } .active{ color: #23527c!important; } </style>
6 如今給每一個過濾的字段都加一個all標籤。
修改get_filter_linktags方法
def get_filter_linktags(self): link_dict = {} # 定義字段對應的a鏈接 {"book":["<a>金平..</a>", "<a>"], ...} for filter_field in self.config.filter_fields: # 獲取要過濾的字段 ["book", "author",..... ] url_params = copy.deepcopy(self.request.GET) # 獲取參數 current_field_id = self.request.GET.get(filter_field, 0) # 獲取當前被選中的字段的id filter_field_obj = self.config.model._meta.get_field(filter_field) # 獲取字段對象 data_list = filter_field_obj.rel.to.objects.all() # 根據字段對象獲取該模型類的queryset對象["book1","book2",...] temp = [] # 定義一個臨時列表 # all標籤 if url_params.get(filter_field): # if GET請求參數中包含當前循環的字段,就把這個參數(字段)刪除 del url_params[filter_field] temp.append("<a href='?%s'>ALL</a>" % url_params.urlencode()) else: # 不存在就說明該字段沒有被選中 temp.append("<a class='active' href='#'>ALL</a>") # 數據標籤 for obj in data_list: url_params[filter_field] = obj.pk _url = url_params.urlencode() if int(current_field_id) == obj.pk: link_tag = "<a class='active' href='?%s'>%s</a>" % (_url, str(obj)) else: link_tag = "<a href='?%s'>%s</a>" % (_url, str(obj)) temp.append(link_tag) link_dict[filter_field] = temp return link_dict
OK 樣式有了,url也有了,進行數據過濾。
7 在ModelStark類中添加get_filter_data方法,並修改list_view方法:
# 過濾數據的查詢條件 def get_filter_data(self, request): filter_condition = Q() for field, pk in request.GET.items(): if field in self.filter_fields: filter_condition.children.append((field, pk)) return filter_condition """列表展現頁""" def list_view(self, request): if request.method == "POST": action_name = request.POST.get("action") # 獲取執行的action名稱 id_list = request.POST.getlist("selected_id") # 獲取被選中的id action_func = getattr(self, action_name) # 反射獲取函數 queryset = self.model.objects.filter(pk__in=id_list) # 過濾被選中的查詢集 action_func(request, queryset) # 執行action return redirect(self.get_list_url()) # 獲取search的key_word,Q對象 key_word, search_connection = self.get_search(request) # 過濾 filter_connection = self.get_filter_data(request) # 獲取userinfo 的數據,並進行search過濾 data_list = self.model.objects.all().filter(search_connection).filter(filter_connection) # 獲取表頭 show_list = ShowList(self, data_list, request) head_list = show_list.show_header() # 獲取表體 new_data_list = show_list.show_body() # 獲取添加的url add_url = self.get_add_url() return render(request, 'list.html', locals())
8 如今就能進行正常的過濾了,只不過如今的能過濾的字段只能是一對多或者多對多。下面處理普通字段的過濾。
修改get_filter_linktags方法
def get_filter_linktags(self): link_dict = {} # 定義字段對應的a鏈接 {"book":["<a>金平..</a>", "<a>"], ...} for filter_field in self.config.filter_fields: # 獲取要過濾的字段 ["book", "author",..... ] url_params = copy.deepcopy(self.request.GET) # 獲取參數 current_field_id = self.request.GET.get(filter_field, 0) # 獲取當前被選中的字段的id filter_field_obj = self.config.model._meta.get_field(filter_field) # 獲取字段對象 if isinstance(filter_field_obj, ForeignKey) or isinstance(filter_field_obj, ManyToManyField): # 若是字段對象是一對多或者多對多 data_list = filter_field_obj.rel.to.objects.all() # 根據字段對象獲取該模型類的queryset對象["book1","book2",...] else: data_list = self.config.model.objects.all().values("pk", filter_field) # 取普通字段的pk和該字段的全部數據 temp = [] # 定義一個臨時列表 # all標籤 if url_params.get(filter_field): # if GET請求參數中包含當前循環的字段,就把這個參數(字段)刪除 del url_params[filter_field] temp.append("<a href='?%s'>ALL</a>" % url_params.urlencode()) else: # 不存在就說明該字段沒有被選中 temp.append("<a class='active' href='#'>ALL</a>") # 數據標籤 for obj in data_list: # 繼續判斷,若是是一對多或者多對多,就用對象去獲取pk和值 if isinstance(filter_field_obj, ForeignKey) or isinstance(filter_field_obj, ManyToManyField): pk = obj.pk text = str(obj) url_params[filter_field] = pk # 字段做爲鍵,pk做爲值 ?publish=1&authors=2 else: pk = obj.get("pk") text = obj.get(filter_field) url_params[filter_field] = text # 字段做爲鍵,實際數據做爲值 ?title="金平沒" _url = url_params.urlencode() if current_field_id == str(pk) or current_field_id == text: link_tag = "<a class='active' href='?%s'>%s</a>" % (_url, text) else: link_tag = "<a href='?%s'>%s</a>" % (_url, text) temp.append(link_tag) link_dict[filter_field] = temp return link_dict
如今在app01 stark.py中的BookConfig類中filter_fields添加"title"字段
class BookConfig(ModelStark): list_display = ["title", "price", "publishDate"] model_class = ModelFormDemo search_fields = ["title", "price"] def edit_price_action(self, request, queryset): queryset.update(price=111) edit_price_action.short_description = "修改價格" actions = [edit_price_action] filter_fields = ["title", "authors", "publish"]
此時頁面上的filter中也能顯示title字段的全部值,而且也能完成過濾。
9 然而如今頁面上不能顯示多對多的字段數據,由於多對多的字段有不止一個值,因此頁面的顯示效果可能會亂,下面作個簡單處理。。
修改ShowList中show_body方法。
def show_body(self): # 獲取表單信息 # 定義一個新的數據列表 格式: """ [ ["name", "age"] ["name", "age"] ....... ] """ new_data_list = [] for obj in self.page_data: # 獲取data_list中的每個對象 temp = [] # 定義一個內層列表,存儲一個對象全部字段的值 for field in self.config.new_list_display(): # 獲取每個要展現的字段 ["name", "age"] if callable(field): # 判斷字段是否可被調用 val = field(self.config, obj) # 給自定義方法傳遞參數 else: field_obj = self.config.model._meta.get_field(field) if isinstance(field_obj, ManyToManyField): vals = getattr(obj, field).all() # 獲取全部數據 new_temp = [] for i in vals: new_temp.append(str(i)) val = ",".join(new_temp) else: val = getattr(obj, field) # field是字符串,利用反射獲取對象每一個字段的值, if field in self.config.list_display_links: # 判斷字段是否在list_display_links中, _url = self.config.get_change_url(obj) val = mark_safe("<a href='%s'>%s</a>" % (_url, val)) temp.append(val) new_data_list.append(temp) return new_data_list
在app01 stark.py中的BookConfig類中list_display添加"authors"字段
此時訪問/stark/app01/book/時, 就能顯示authors這一列了。可是若是咱們訪問其餘model的列表頁時可能會報錯,假如訪問stark/app01/author/,而後就會有這樣的提示
這是由於(以author表爲例):若是用戶沒有給author配置list_display,那麼就會使用默認的__str__,可是當程序走到show_body的這裏時,
查不到__str__的字段對象,所以會報錯。解決辦法,異常捕獲。
修改show_body方法,show_body代碼:
def show_body(self): # 獲取表單信息 # 定義一個新的數據列表 格式: """ [ ["name", "age"] ["name", "age"] ....... ] """ new_data_list = [] for obj in self.page_data: # 獲取data_list中的每個對象 temp = [] # 定義一個內層列表,存儲一個對象全部字段的值 for field in self.config.new_list_display(): # 獲取每個要展現的字段 ["name", "age"] if callable(field): # 判斷字段是否可被調用 val = field(self.config, obj) # 給自定義方法傳遞參數 else: try: field_obj = self.config.model._meta.get_field(field) if isinstance(field_obj, ManyToManyField): vals = getattr(obj, field).all() # 獲取全部數據 new_temp = [] for i in vals: new_temp.append(str(i)) val = ",".join(new_temp) else: val = getattr(obj, field) # field是字符串,利用反射獲取對象每一個字段的值, if field in self.config.list_display_links: # 判斷字段是否在list_display_links中, _url = self.config.get_change_url(obj) val = mark_safe("<a href='%s'>%s</a>" % (_url, val)) except Exception as e: val = getattr(obj, field) temp.append(val) new_data_list.append(temp) return new_data_list
pop
當咱們在admin添加數據的時候,若是哪一個字段和其餘表有關聯,能夠在輸入框的後面點擊加號去添加關聯表的數據。下面作這個功能。
1 修改添加頁面的樣式,修改add_view.html,由於add_view.html使用form.html,所以在form.html上修改。
<div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <form action="" method="post" novalidate> {% csrf_token %} {% for field in form_obj %} <div style="position: relative"> <label for="">{{ field.label }}</label> {{ field }} <span style="color: red" class=" error pull-right">{{ field.errors.0 }}</span> <a style="position: absolute;right: -30px;top: 20px;text-decoration: none;cursor: pointer"><span style="font-size: 28px">+</span></a> </div> {% endfor %} <button type="submit" class="btn btn-default pull-right">提交</button> </form> </div> </div> </div>
此時頁面上每一個表單的後面都有加號按鈕,可是一些和其餘表沒有關聯的字段是不該該有加號的,所以應該在後臺進行判斷。由於使用的是ModelForm組件,所以判斷字段的類型是否是ModelChoiceField便可。
2 修改ModelStark類中的add_view
def add_view(self, request): ModelFormDemo = self.get_modelform_class() # 取到的是類名 form_obj = ModelFormDemo() for bfield in form_obj: if isinstance(bfield.field, ModelChoiceField): # bfield.field 獲取的是字段對象;bfield.name 獲取的是字段名稱,類型是字符串; bfield.is_related = True if request.method == "POST": form_obj = ModelFormDemo(request.POST) if form_obj.is_valid(): form_obj.save() return redirect(self.get_list_url()) return render(request, 'add_view.html', locals())
這時候只有publish和author後面有加號。
3 如今是作點擊事件,修改form.html,給a標籤添加一個click事件,讓它跳轉到對應的添加頁面,所以還須要一個url。
先去add_view把url獲取了
def add_view(self, request): ModelFormDemo = self.get_modelform_class() # 取到的是類名 form_obj = ModelFormDemo() for bfield in form_obj: if isinstance(bfield.field, ModelChoiceField): # bfield.field 獲取的是字段對象;bfield.name 獲取的是字段名稱,類型是字符串; bfield.is_related = True # 獲取該字段的模型表和模型表的app # bfield.field.queryset.model 一對多或者多對多字段的關聯模型表 relateed_model_name = bfield.field.queryset.model._meta.model_name relateed_app_label = bfield.field.queryset.model._meta.app_label _url = reverse("%s_%s_add" % (relateed_app_label, relateed_model_name)) bfield.add_url = _url
4 修改form.html,給a標籤添加一個click事件
<div class="container"> <div class="row"> <div class="col-md-6 col-xs-10 col-md-offset-3"> <form action="" method="post" novalidate> {% csrf_token %} {% for field in form_obj %} <div style="position: relative"> <label for="">{{ field.label }}</label> {{ field }} <span style="color: red" class=" error pull-right">{{ field.errors.0 }}</span> {% if field.is_related %} <a onclick="pop('{{ field.add_url }}')" style="position: absolute;right: -30px;top: 20px;text-decoration: none;cursor: pointer"><span style="font-size: 28px">+</span></a> {% endif %} </div> {% endfor %} <button type="submit" class="btn btn-default pull-right">提交</button> </form> </div> </div> </div> <script> function pop(url) { window.open(url,"", "width=600,height=400,top=100,left=100") } </script>
如今就能點擊加號而後跳轉到對應的模型添加頁面。
Ok ,如今能跳轉到對應的添加頁面,可是咱們須要知道在添加完數據以後給哪一個字段添加數據,而且在提交表單以後要返回添加的數據,並且要把值放到字段對應的select標籤裏。
解決步驟:(book添加頁面爲例)
(1)給url加參數,修改add_view方法,在每條url的後面加上一個參數,以pop_id爲鍵,字段名爲值,即只修改下面這句代碼:
bfield.add_url = _url+"?pop_id=id_%s" % bfield.name # id_%s 和select標籤的id對應
當點擊publish後面加號時,會彈出一個publish添加頁面的小窗口。然而在添加完數據後會跳到publish的列表頁,可是並不但願跳到列表頁,而是返回以前的book添加頁面。而且返回book的添加頁面時,把剛纔添加的publish數據放到publish的select裏。所以須要一個一個頁面做爲中間人來處理。這個中間人須要完成的工做:1.執行add_view.html中的js,將publish的添加數據放在publish下拉列表中;2. 關閉publish添加頁面的小窗口。
(2) 首先修改add_view方法中對request.POST的處理:
def add_view(self, request): ModelFormDemo = self.get_modelform_class() # 取到的是類名 form_obj = ModelFormDemo() for bfield in form_obj: if isinstance(bfield.field, ModelChoiceField): # bfield.field 獲取的是字段對象;bfield.name 獲取的是字段名稱,類型是字符串; bfield.is_related = True # 獲取該字段的模型表和模型表的app # bfield.field.queryset.model 一對多或者多對多字段的關聯模型表 relateed_model_name = bfield.field.queryset.model._meta.model_name relateed_app_label = bfield.field.queryset.model._meta.app_label _url = reverse("%s_%s_add" % (relateed_app_label, relateed_model_name)) bfield.add_url = _url+"?pop_id=id_%s" % bfield.name # id_%s 和select標籤的id對應 if request.method == "POST": form_obj = ModelFormDemo(request.POST) if form_obj.is_valid(): obj = form_obj.save() pop_id = request.GET.get("pop_id") if pop_id: # 判斷是否爲小窗口的添加 ret = {"pk": obj.pk, "value": str(obj), "pop_id": pop_id} return render(request, 'pop.html', ret) else: return redirect(self.get_list_url()) return render(request, 'add_view.html', locals())
(3)添加pop.html文件
(4)修改add_view.html,添加js
<script> function pop_response(pk, text, field_name) { // 建立一個option標籤 var $option = $("<option>"); $option.val(pk); $option.text(text); $option.attr("selected", "selected"); $("#"+field_name).append($option); } </script>
(5)修改pop.html,添加js
<script> window.opener.pop_response("{{ pk }}", "{{ value }}", "{{ pop_id }}"); window.close(); </script>
如今就實現pop了。也算是實現了自定義的admin的增刪改查。