模型层
1 from django.db import models 2 # Create your models here. 3 4 class Author(models.Model): 5 nid = models.AutoField(primary_key=True) 6 name=models.CharField( max_length=32) 7 age=models.IntegerField() 8 # 与AuthorDetail建立一对一的关系 9 authorDetail=models.OneToOneField(to="AuthorDetail",on_delete=models.CASCADE) 10 def __str__(self): 11 return self.name 12 13 class AuthorDetail(models.Model): 14 nid = models.AutoField(primary_key=True) 15 birthday=models.DateField() 16 telephone=models.BigIntegerField() 17 addr=models.CharField( max_length=64) 18 19 class Publish(models.Model): 20 nid = models.AutoField(primary_key=True) 21 name=models.CharField( max_length=32) 22 city=models.CharField( max_length=32) 23 email=models.EmailField() 24 def __str__(self): 25 return self.name 26 27 class Book(models.Model): 28 nid = models.AutoField(primary_key=True,verbose_name=" 编号") 29 title = models.CharField( max_length=32,verbose_name="书籍名称") 30 publishDate=models.DateField() 31 price=models.DecimalField(max_digits=5,decimal_places=2) 32 # 与Publish建立一对多的关系,外键字段建立在多的一方 33 publish=models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE) 34 # 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表 35 authors=models.ManyToManyField(to='Author',) 36 def __str__(self): 37 return self.title
模板层
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css"> 7 <link rel="stylesheet" href="/static/css/common.css"> 8 </head> 9 <body> 10 <h3>添加数据</h3> 11 <div class="container"> 12 <div class="row"> 13 <div class="col-md-6 col-md-offset-3"> 14 {% include 'form.html' %} 15 </div> 16 </div> 17 </div> 18 </body> 19 </html>
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 </head> 7 <body> 8 <h3>删除数据</h3> 9 {{ l }} 10 {{ l.0 }} 11 <form action="" method="post"> 12 {% csrf_token %} 13 <input type="submit" value="确认删除"> 14 <a href="{{ list_url }}">取消</a> 15 </form> 16 </body> 17 </html>
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css"> 7 <link rel="stylesheet" href="/static/css/common.css"> 8 </head> 9 <body> 10 <h3>编辑数据</h3> 11 <div class="container"> 12 <div class="row"> 13 <div class="col-md-6 col-md-offset-3"> 14 {% include 'form.html' %} 15 </div> 16 </div> 17 </div> 18 </body> 19 </html>
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css"> 7 <link rel="stylesheet" href="/static/css/list_view.css"> 8 </head> 9 <body> 10 <h3>查看{{ model_name }}数据</h3> 11 <div class="container"> 12 <div class="row"> 13 <div class="col-md-9"> 14 <a href="{{ add_url }}" class="btn btn-info add_btn">添加</a> 15 {% if show_list.config.search_fields %} 16 <form action="" class="pull-right" method="get"> 17 <input style="display: inline-block; 300px" type="text" name="q" class="form-control"><input type="submit" value="search" class="btn btn-success"> 18 </form> 19 {% endif %} 20 21 <form action="" method="post"> 22 {% csrf_token %} 23 <div> 24 <select name="action" id="" class="form-control" style="display: inline-block; 300px"> 25 <option value="">---------------</option> 26 27 {% for action_dict in show_list.new_actions %} 28 <option value="{{ action_dict.name }}">{{ action_dict.desc }}</option> 29 {% endfor %} 30 31 </select> 32 <input type="submit" value="Go" class="btn btn-warning"> 33 34 </div> 35 <table class="table table-bordered table-striped"> 36 <thead> 37 <tr> 38 {% for item in show_list.get_header %} 39 <th>{{ item }}</th> 40 {% endfor %} 41 42 </tr> 43 </thead> 44 <tbody> 45 {% for new_data in show_list.get_body %} 46 <tr> 47 {% for item in new_data %} 48 <td>{{ item }}</td> 49 {% endfor %} 50 </tr> 51 {% endfor %} 52 53 </tbody> 54 </table> 55 56 </form> 57 58 <div class="pull-right"> {{ show_list.pagination.page_html|safe }}</div> 59 </div> 60 <div class="col-md-3"> 61 {% for filter_filed,link_tag_list in show_list.get_filter_link_tags.items %} 62 <p>By {{ filter_filed.upper }}</p> 63 {% for link_tag in link_tag_list %} 64 <p>{{ link_tag }}</p> 65 {% endfor %} 66 {% endfor %} 67 </div> 68 </div> 69 </div> 70 71 </body> 72 </html>
<form action="" method="post" novalidate> {% csrf_token %} {% for filed in form %} <div class="form-group"> <label for="">{{ filed.label }}</label> {{ filed }} <span>{{ filed.errors.0 }}</span> </div> {% endfor %} <input type="submit" class="btn btn-default"> </form>
Xadmin函数
from django.conf.urls import url from django.shortcuts import HttpResponse,render,redirect from django.urls import reverse from django.utils.safestring import mark_safe from Xadmin.utils.page import Pagination from django.db.models import Q class ShowList(object): def __init__(self,config,request,data_list): self.config=config self.data_list=data_list self.request=request # 分页器组件相关配置 current_page=request.GET.get("page") all_count=self.data_list.count() pagination=Pagination(current_page,all_count,request.GET) self.pagination=pagination self.page_data_list=self.data_list[pagination.start:pagination.end] self.actions=self.config.get_actions() # list_filter self.list_filter=self.config.list_filter # ["publish","auhtors] def get_filter_link_tags(self): #link_tags={"publish":["a","a"],"author":["a","a"]} link_tags={} from copy import deepcopy for filter_field in self.list_filter: # ["publish","auhtors] params = deepcopy(self.request.GET) # {"authors":2} current_id=self.request.GET.get(filter_field) print("current_id",current_id) filter_field_obj=self.config.model._meta.get_field(filter_field) related_data_list=filter_field_obj.rel.to.objects.all() temp=[] for obj in related_data_list: params[filter_field]=obj.pk _url=params.urlencode() if current_id==str(obj.pk): s="<a class='item' href='?%s'>%s</a>"%(_url,str(obj)) else: s = "<a href='?%s'>%s</a>" % (_url, str(obj)) temp.append(mark_safe(s)) link_tags[filter_field]=temp return link_tags def new_actions(self): temp=[] for action in self.actions: temp.append({ "name":action.__name__, "desc":action.short_description }) print("temp",temp) return temp def get_header(self): # 处理表头 # header_list=["ID","书籍名称","出版社"] header_list = [] for field in self.config.new_list_display(): # [check,"nid","title","publish",edit,delete] if isinstance(field, str): if field == "__str__": val = self.config.model._meta.model_name.upper() else: field_obj = self.config.model._meta.get_field(field) val = field_obj.verbose_name else: val = field(self.config, is_header=True) # 获取表头,传is_header=True header_list.append(val) return header_list def get_body(self): # 处理表单数据 new_data_list = [] for obj in self.page_data_list: # data_list [book_obj,book_obj2,...] temp = [] for field in self.config.new_list_display(): # ["nid","title","publish","authors"] if isinstance(field, str): try: from django.db.models.fields.related import ManyToManyField field_obj = self.config.model._meta.get_field(field) if isinstance(field_obj, ManyToManyField): t = [] for i in getattr(obj, field).all(): t.append(str(i)) val = ",".join(t) else: if field in self.config.list_display_link: edit_url = self.config.get_edit_url(obj) val = mark_safe("<a href='%s'>%s</a>" % (edit_url, getattr(obj, field))) else: val = getattr(obj, field) except Exception as e: val = getattr(obj, field) else: val = field(self.config, obj) temp.append(val) new_data_list.append(temp) ''' new_data_list=[ ["北京折叠",122,<a href=''>编辑</a>,<a href=''>删除</a>], ["三体", 222,<a href=''>编辑</a>,<a href=''>删除</a>], ] ''' return new_data_list class ModelXadmin(object): list_display=["__str__",] list_display_link=[] search_fields=[] actions=[] list_filter=[] def patch_delete(self,request,queryset): queryset.delete() patch_delete.short_description="批量删除" def get_actions(self): temp=[] temp.extend(self.actions) temp.append(self.patch_delete) return temp model_form_class=None def __init__(self,model,site): self.model=model self.site=site self.model_name="" self.app_name="" # 选择按钮 编辑 删除 def edit(self, obj=None, is_header=False): if is_header: return "操作" _url=self.get_edit_url(obj) return mark_safe("<a href='%s'>编辑</a>" % _url) def delete(self, obj=None, is_header=False): if is_header: return "操作" _url=self.get_delete_url(obj) return mark_safe("<a href='%s'>删除</a>"%_url) def checkbox(self, obj=None, is_header=False): if is_header: return "选择" return mark_safe("<input type='checkbox' name='selected' value='%s'>"%obj.pk) # 反向解析当前表的增删改查的url def get_edit_url(self,obj): # 反向解析:url url_name = "%s_%s_change" % (self.app_name, self.model_name) # http://127.0.0.1:8008/Xadmin/app01/book/(d+)/change _url = reverse(url_name, args=(obj.pk,)) # return mark_safe("<a href='%s/change/'>编辑</a>"%obj.pk) return _url def get_list_url(self): # 反向解析:url url_name = "%s_%s_list" % (self.app_name, self.model_name) _url = reverse(url_name) return _url def get_add_url(self): # 反向解析:url url_name = "%s_%s_add" % (self.app_name, self.model_name) _url = reverse(url_name) return _url def get_delete_url(self,obj): # 反向解析:url url_name = "%s_%s_delete" % (self.app_name, self.model_name) _url = reverse(url_name, args=(obj.pk,)) return _url # 构建新的展示列表,默认加入选择按钮 编辑 删除 def new_list_display(self): temp=[] temp.append(ModelXadmin.checkbox) temp.extend(self.list_display) if not self.list_display_link: temp.append(ModelXadmin.edit) temp.append(ModelXadmin.delete) return temp def get_search_condition(self,request): search_condition = Q() search_condition.connector = "or" print("search_fields", self.search_fields) # ["title","price"] key_word = request.GET.get('q') if key_word: for search_field in self.search_fields: search_condition.children.append((search_field + "__icontains", key_word)) return search_condition # 查看视图函数 def list_view(self, request): """ self.model: 用户访问哪张表,self.model就是谁 data_list: 查看表下的数据 ShowList(self,data_list) # self: 当前查看表的配置类对象 :param request: :return: """ if request.method=="POST":# action print(request.POST) action=request.POST.get("action") selected_pk_list=request.POST.getlist("selected") queryset=self.model.objects.filter(pk__in=selected_pk_list) action=getattr(self,action) ret=action(request,queryset) return ret search_condition=self.get_search_condition(request) filter_condition=Q() for filter_field,val in request.GET.items(): if filter_field not in ["page","q"]: filter_condition.children.append((filter_field,val)) data_list = self.model.objects.filter(filter_condition).filter(search_condition) show_list=ShowList(self,request,data_list) add_url = self.get_add_url() model_name = self.model._meta.model_name return render(request, 'list_view.html', {"model_name":model_name,"add_url":add_url,"show_list":show_list}) # 获取modelForm类 def get_model_form_class(self): if self.model_form_class: return self.model_form_class else: from django.forms import ModelForm class DemoModelForm(ModelForm): class Meta: model=self.model fields="__all__" return DemoModelForm # 添加视图函数 def add_view(self, request): DemoModelForm = self.get_model_form_class() if request.method=="POST": form=DemoModelForm(request.POST) if form.is_valid(): form.save() return redirect(self.get_list_url()) else: return render(request, 'add_view.html', locals()) form=DemoModelForm return render(request, 'add_view.html',locals()) # 编辑视图函数 def change_view(self, request, id): edit_obj=self.model.objects.get(pk=id) DemoModelForm=self.get_model_form_class() if request.method=="POST": form=DemoModelForm(request.POST,instance=edit_obj) if form.is_valid(): form.save() return redirect(self.get_list_url()) else: return render(request, 'change_view.html', locals()) form=DemoModelForm(instance=edit_obj) return render(request, 'change_view.html',locals()) # 删除视图函数 def delete_view(self, request, id): list_url = self.get_list_url() if request.method=="POST": self.model.objects.filter(pk=id).delete() return redirect(list_url) class Per(): def __init__(self): pass return render(request, 'delete_view.html',{"list_url":list_url}) def get_urls2(self): temp = [] self.app_name = self.model._meta.app_label # "app01" self.model_name = self.model._meta.model_name # "book" temp.append(url(r"^$", self.list_view,name="%s_%s_list"%(self.app_name,self.model_name))) temp.append(url(r"^add/$", self.add_view,name="%s_%s_add"%(self.app_name,self.model_name))) temp.append(url(r"^(d+)/change/$", self.change_view,name="%s_%s_change"%(self.app_name,self.model_name))) temp.append(url(r"^(d+)/delete/$", self.delete_view,name="%s_%s_delete"%(self.app_name,self.model_name))) return temp # 路由二级分发 @property def urls2(self): return self.get_urls2(), None, None class XadminSite(object): def __init__(self, name='admin'): self._registry = {} def get_urls(self): print(self._registry) # {Book:modelAdmin(Book),.......} temp = [] for model, admin_class_obj in self._registry.items(): # 获取当前循环的model的字符串与所在app的字符串 app_name = model._meta.app_label # "app01" model_name = model._meta.model_name # "book" temp.append(url(r'^{0}/{1}/'.format(app_name, model_name),admin_class_obj.urls2), ) ''' url(r"app01/book",ModelXadmin(Book,site).urls2) url(r"app01/publish",ModelXadmin(Publish,site).urls2) url(r"app02/order",ModelXadmin(Order,site).urls2) ''' return temp @property def urls(self): return self.get_urls(),None,None def register(self, model, admin_class=None, **options): if not admin_class: admin_class = ModelXadmin self._registry[model] = admin_class(model, self) # {Book:ModelAdmin(Book),Publish:ModelAdmin(Publish)} site=XadminSite()
1 from django.contrib import admin 2 3 # Register your models here. 4 5 from django.shortcuts import HttpResponse 6 from Xadmin.service.Xadmin import site,ModelXadmin 7 from app01.models import * 8 from django.utils.safestring import mark_safe 9 from django.urls import reverse 10 from app01.models import Book 11 from django.forms import ModelForm 12 13 14 # 建立表单 15 class BookModelForm(ModelForm): 16 class Meta: 17 model=Book 18 fields="__all__" 19 error_messages={ 20 "title":{"required":"该字段不能为空!"} 21 } 22 23 # 建立表单 24 class BookConfig(ModelXadmin): 25 def display_authors(self,obj=None,is_header=False): 26 if is_header: 27 return "作者" 28 s=[] 29 for author in obj.authors.all(): 30 s.append(author.name) 31 32 return mark_safe(" ".join(s)) 33 34 list_display=["nid","title","price","publish","authors"] 35 #list_display=["nid","title","publish"] 36 37 model_form_class=BookModelForm 38 list_display_link=["nid","title"] 39 search_fields=["title","price"] 40 41 # action 42 def patch_init(self, request, queryset): 43 44 print(queryset) 45 queryset.update(price=100) 46 47 return HttpResponse("修改成功") 48 49 patch_init.short_description = "批量初始化" 50 51 def foo(self):pass 52 53 foo.short_description = "批量初始化" 54 55 actions = [foo,patch_init,] 56 57 list_filter = ["publish","authors"] 58 59 60 site.register(Book,BookConfig) 61 site.register(Publish) 62 site.register(Author) 63 site.register(AuthorDetail)
其他控件
分页
1 """ 2 分页组件使用示例: 3 4 obj = Pagination(request.GET.get('page',1),len(USER_LIST),request.path_info) 5 page_user_list = USER_LIST[obj.start:obj.end] 6 page_html = obj.page_html() 7 8 return render(request,'index.html',{'users':page_user_list,'page_html':page_html}) 9 10 """ 11 class Pagination(object): 12 13 def __init__(self,current_page,all_count,params,per_page_num=2,pager_count=11): 14 """ 15 封装分页相关数据 16 :param current_page: 当前页 17 :param all_count: 数据库中的数据总条数 18 :param per_page_num: 每页显示的数据条数 19 :param base_url: 分页中显示的URL前缀 20 :param pager_count: 最多显示的页码个数 21 """ 22 23 try: 24 current_page = int(current_page) 25 except Exception as e: 26 current_page = 1 27 28 if current_page <1: 29 current_page = 1 30 31 self.current_page = current_page 32 self.all_count = all_count 33 self.per_page_num = per_page_num 34 35 36 37 # 总页码 38 all_pager, tmp = divmod(all_count, per_page_num) 39 if tmp: 40 all_pager += 1 41 self.all_pager = all_pager 42 self.pager_count = pager_count 43 self.pager_count_half = int((pager_count - 1) / 2) 44 45 46 47 # GET请求数据 48 import copy 49 self.params=copy.deepcopy(params) # request.GET {"nid":1} 50 51 @property 52 def start(self): 53 return (self.current_page - 1) * self.per_page_num 54 55 @property 56 def end(self): 57 return self.current_page * self.per_page_num 58 59 def page_html(self): 60 # 如果总页码 < 11个: 61 if self.all_pager <= self.pager_count: 62 pager_start = 1 63 pager_end = self.all_pager + 1 64 # 总页码 > 11 65 else: 66 # 当前页如果<=5 67 if self.current_page <= self.pager_count_half: 68 pager_start = 1 69 pager_end = self.pager_count + 1 70 71 # 当前页大于5 72 else: 73 # 页码翻到最后 74 if (self.current_page + self.pager_count_half) > self.all_pager: 75 pager_start = self.all_pager - self.pager_count + 1 76 pager_end = self.all_pager + 1 77 78 else: 79 pager_start = self.current_page - self.pager_count_half 80 pager_end = self.current_page + self.pager_count_half + 1 81 82 83 84 page_html_list = [] 85 86 page_html_list.append('<nav aria-label="Page navigation"><ul class="pagination">') 87 88 89 first_page = '<li><a href="?page=%s">首页</a></li>' % 1 90 page_html_list.append(first_page) 91 92 if self.current_page <= 1: 93 prev_page = '<li class="disabled"><a href="#">上一页</a></li>' 94 else: 95 prev_page = '<li><a href="?page=%s">上一页</a></li>' % (self.current_page - 1,) 96 97 page_html_list.append(prev_page) 98 99 100 # self.params {"nid":1} 101 102 for i in range(pager_start, pager_end): 103 104 self.params["page"]=i 105 106 if i == self.current_page: 107 temp = '<li class="active"><a href="?%s">%s</a></li>' % (self.params.urlencode(), i,) 108 else: 109 temp = '<li><a href="?%s">%s</a></li>' % (self.params.urlencode(), i,) 110 page_html_list.append(temp) 111 112 if self.current_page >= self.all_pager: 113 next_page = '<li class="disabled"><a href="#">下一页</a></li>' 114 else: 115 next_page = '<li><a href="?page=%s">下一页</a></li>' % (self.current_page + 1,) 116 page_html_list.append(next_page) 117 118 last_page = '<li><a href="?page=%s">尾页</a></li>' % (self.all_pager,) 119 page_html_list.append(last_page) 120 121 page_html_list.append('</ul></nav>') 122 123 return ''.join(page_html_list)