CRM

模型层

 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)
分页
原文地址:https://www.cnblogs.com/cangshuchirou/p/9152497.html