zoukankan      html  css  js  c++  java
  • crm02 stark组件(自定义Django-admin)之运行流程

    项目目录结构:                    

       

    配置文件加载 setting.py  会从上至下加载每个app的app.py文件

    第一步:循环加载执行所有已经注册的app中的stark.py文件

    ###### app01/app.py ###### 
    from django.apps import AppConfig
    
    class App01Config(AppConfig):
        name = 'app01'
    
    
    ###### app02/app.py ###### 
    from django.apps import AppConfig
    
    class App02Config(AppConfig):
        name = 'app02'
    
    
    ###### stark/app.py ###### 
    from django.apps import AppConfig
    
    from django.utils.module_loading import autodiscover_modules
    class StarkConfig(AppConfig):
        name = 'stark'
        def ready(self):  #ready方法在加载的时候会执行
            autodiscover_modules('stark') # 扫描加载所有已经注册的app中的stark.py文件

    第二步: 执行代码

    ###### app01/stark.py ######
    from stark.service.sites import site,ModelStark
    from .models import *
    from django.utils.safestring import mark_safe
    
    class BookConfig(ModelStark):
    
        #自定义列
        def show_authors(self,obj=None,header=False):
            if header:
                return "作者信息"
            return " ".join([author.name for author in obj.authors.all()])
    
    
        list_display=["title","price","state","publish",show_authors]
    
    
    site.register(Book,BookConfig)
    site.register(Publish)
    print(site._registry)
    
    ###### app02/stark.py ######
    print("234")

    第三步 所有的app中的stark.py里面 都是调用 stark/service/sites.py 的site

    这里应用的是一个单例模式,对于StarkSite类的一个单例模式,执行的每一个app中的每一个site都是同一个实例对象

    第四步 执行register方法(代码在第二步里面)

    site.register(Book,BookConfig)
    site.register(Publish)
    class StarkSite:
        '''
        stark全局类
        '''
        def __init__(self):
            self._registry = {}
    
        def register(self, model, admin_class=None, **options):
            admin_class = admin_class or ModelStark
            self._registry[model] = admin_class(model)

    思考:在每一个app的admin .py中加上

    print(site._registry) # 执行结果{模型对象:配置类对象(模型类名)}? 
    {<class 'app01.models.Book'>: <app01.stark.BookConfig object at 0x0000015EC8F21B38>, <class 'app01.models.Publish'>: <stark.service.sites.ModelStark object at 0x0000015EC8F21E10>}

    到这里,注册结束!

    <5> admin的URL配置

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
    ]
    复制代码
    class AdminSite(object):
        
         def get_urls(self):
            from django.conf.urls import url, include
          
            urlpatterns = []
    
            # Add in each model's views, and create a list of valid URLS for the
            # app_index
            valid_app_labels = []
            for model, model_admin in self._registry.items():
                urlpatterns += [
                    url(r'^%s/%s/' % (model._meta.app_label, model._meta.model_name), include(model_admin.urls)),
                ]
                if model._meta.app_label not in valid_app_labels:
                    valid_app_labels.append(model._meta.app_label)
    
          
            return urlpatterns
    
        @property
        def urls(self):
            return self.get_urls(), 'admin', self.name
    复制代码

    <6>  url()方法的扩展应用

    复制代码
    from django.shortcuts import HttpResponse
    def test01(request):
        return HttpResponse("test01")
    
    def test02(request):
        return HttpResponse("test02")
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^yuan/', ([
                        url(r'^test01/', test01),
                        url(r'^test02/', test02),
    
                        ],None,None)),
    
    ]
    复制代码

    扩展优化

    全代码01版

    # -*- coding: utf-8 -*-
    # @Time    : 2019/4/12 11:51
    # @Author  : xxx
    # @Email   : xxx@admin.com
    # @File    : sites.py
    # @Software: PyCharm
    from django.urls import path,re_path
    from django.shortcuts import HttpResponse,render
    from app01.models import *
    from django.utils.safestring import mark_safe
    from django.urls import reverse
    
    class ModelStark(object):
        '''
        默认配置类
        '''
        list_display=("__str__",)
        def __init__(self,model):  #self  当前访问模型表对应的配置类对象 eg:<app01.stark.BookConfig object at 0x0000019BEBC88710>
            self.model=model  #self.model   当前访问模型表  eg:<class 'app01.models.Book'>
            self.model_name = self.model._meta.model_name #模型表的名字  eg:book
            self.app_label = self.model._meta.app_label #app的名字 eg:app01
    
        # 反向解析当前访问表的增删改查URL
        def get_list_url(self):
            # 反向解析当前表的删除的URL
            list_url = reverse("%s_%s_list" % (self.app_label, self.model_name))
            return list_url
    
        def get_add_url(self,obj):
            # 反向解析当前表的删除的URL
            add_url = reverse("%s_%s_delete" % (self.app_label, self.model_name))
            return add_url
    
        def get_delete_url(self,obj):
            # 反向解析当前表的删除的URL
            delete_url = reverse("%s_%s_delete" % (self.app_label, self.model_name), args=(obj.pk,))
            return delete_url
    
        def get_change_url(self, obj):
            # 反向解析当前表的删除的URL
            change_url = reverse("%s_%s_change" % (self.app_label, self.model_name), args=(obj.pk,))
            return change_url
    
        # 三个默认列
        def show_checkbox(self, obj=None, header=False):
            if header:
                return mark_safe("<input type='checkbox'>")
            return mark_safe("<input type='checkbox'>")
    
        def show_delbtn(self, obj=None, header=False):
            if header:
                return "删除"
    
            return mark_safe("<a href='%s'>删除</a>"%self.get_delete_url(obj))
    
        def show_editbtn(self, obj=None, header=False):
            if header:
                return "编辑"
            return mark_safe("<a href='%s'>编辑</a>" %self.get_change_url(obj))
    
        #  构建新的list_display
    
        def get_new_list_display(self):
            temp=[]
            temp.extend(self.list_display)
            temp.append(ModelStark.show_editbtn)
            temp.append(ModelStark.show_delbtn)
            temp.insert(0,ModelStark.show_checkbox)
    
            return temp
    
        #  视图函数
        def list_view(self,request):
            '''
            self: 当前访问模型表对应的配置类对象
            self.model: 当前访问模型表
            :param request:
            :return:
            '''
    
            queryset=self.model.objects.all()
            print(queryset) #eg:<QuerySet [<Book: python>, <Book: java>]>
            print(self.list_display) # eg:['title', 'price', 'state', 'publish', <function BookConfig.show_authors at 0x0000016D70D74840>]
            print(self.get_new_list_display())
            #[<function ModelStark.show_checkbox at 0x00000267120451E0>, 'title', 'price', 'state', 'publish', <function BookConfig.show_authors at 0x0000026711D14840>, <function ModelStark.show_editbtn at 0x00000267120452F0>, <function ModelStark.show_delbtn at 0x0000026712045268>]
            #   构建表头
            header_list=[]
            for field_or_func in self.get_new_list_display():
                if callable(field_or_func):
                    val=field_or_func(self,header=True)
                    header_list.append(val)
                    #header_list.append(field_or_func.__name__)
                else:
                     if field_or_func=="__str__":
                         val=self.model._meta.model_name.upper()
                         print(val)
                     else:
                          field_obj = self.model._meta.get_field(field_or_func)
                          val=field_obj.verbose_name
                     header_list.append(val)
    
            #  构建展示数据
            new_data=[]
            for obj in queryset:
                temp=[]
    
                for field_or_func in self.get_new_list_display(): #
                    if callable(field_or_func):
                        #  field:方法
                        val=field_or_func(self,obj)
                    else:
                        try:
                            #  field:字符串
                            from django.db.models.fields.related import ManyToManyField
                            field_obj=self.model._meta.get_field(field_or_func)
                            #  判断是否多对多字段
                            if type(field_obj)==ManyToManyField:
                                raise Exception("list_display不能是多对多字段!")
                            #  判断字段是否 拥有choices属性
                            if field_obj.choices:
                                val=getattr(obj,"get_%s_display"%field_or_func)()
                            else:
                                val=getattr(obj,field_or_func)
                        except Exception as e:
                            #val=obj
                            val=getattr(obj,field_or_func)()
                            #如果没有自定义配置类  就会采用默认配置类ModelStark  此时就会getattr(obj,__str__)()   obj是模型类
    
                    temp.append(val)
                new_data.append(temp)
    
    
            print("new_data",new_data)
            #new_data [["<input type='checkbox'>", 'python', Decimal('123.00'), '已出版', <Publish: 苹果出版设>, 'alex egon', "<a href='/stark/app01/book/1/change/'>编辑</a>", "<a href='/stark/app01/book/1/delete/'>删除</a>"],
            #  ["<input type='checkbox'>", 'java', Decimal('234.00'), '已出版', <Publish: 橘子出版设>, 'egon', "<a href='/stark/app01/book/2/change/'>编辑</a>", "<a href='/stark/app01/book/2/delete/'>删除</a>"]]
    
    
            '''
            目标数据结构
            new_data=[
                ["python",123],
                ["java",234]
            ]
            '''
    
            return render(request,'stark/list_view.html',locals())
    
        def add_view(self,request):
            return HttpResponse("add_view")
    
        def change_view(self,request, id):
            return HttpResponse("change_view")
    
        def delete_view(self,request, id):
            return HttpResponse("delete_view")
    
        @property
        def get_urls(self):
    
    
    
    
            temp = [
                path("", self.list_view,name="%s_%s_list"%(self.app_label,self.model_name)),
                path("add/", self.add_view,name="%s_%s_add"%(self.app_label,self.model_name)),
                re_path("(d+)/change/", self.change_view,name="%s_%s_change"%(self.app_label,self.model_name)),
                re_path("(d+)/delete/", self.delete_view,name="%s_%s_delete"%(self.app_label,self.model_name)),
            ]
    
            return (temp, None, None)
    
    class StarkSite:
        '''
        stark全局类
        '''
        def __init__(self):
            self._registry = {}
    
        def register(self, model, admin_class=None, **options):
            admin_class = admin_class or ModelStark
            self._registry[model] = admin_class(model)
    
    
        def get_urls(self):
            #  动态为注册的模型类创建增删改查URL
            temp = []
            # {Book:ModelAdmin(Book),Publish:ModelAdmin(Publish)}
            for model, config_obj in self._registry.items():
                print("---->", model, config_obj)
                model_name = model._meta.model_name
                app_label = model._meta.app_label
                temp.append(
                    path("%s/%s/" % (app_label,model_name),config_obj.get_urls)
                )
    
            '''
               path("stark/app01/book",BookConfig(Book).list_view)
               path("stark/app01/book/add",BookConfig(Book).add_view)      
               path("stark/app01/publish",ModelAdmin(Publish).list_view)
               path("stark/app01/publish/add",ModelAdmin(Publish).add_view)
            
            '''
    
            return temp
    
        @property
        def urls(self):
            return self.get_urls(),None,None
    
    site = StarkSite()
    stark/service/sites.py
    # -*- coding: utf-8 -*-
    # @Time    : 2019/4/12 11:47
    # @Author  : xxx
    # @Email   : xxx@admin.com
    # @File    : stark.py
    # @Software: PyCharm
    
    from stark.service.sites import site,ModelStark
    from .models import *
    from django.utils.safestring import mark_safe
    
    class BookConfig(ModelStark):
    
        def show_authors(self,obj=None,header=False):
            if header:
                return "作者信息"
            return " ".join([author.name for author in obj.authors.all()])
    
    
        list_display=["title","price","state","publish",show_authors]
    
    
    site.register(Book,BookConfig)
    site.register(Publish)
    print(site._registry)
    app01/stark.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()
        def __str__(self):
            return self.name
    
    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,verbose_name="书籍名称")
        # publishDate=models.DateField()
        price=models.DecimalField(max_digits=5,decimal_places=2,verbose_name="价格")
        state=models.IntegerField(choices=[(1,"已出版"),(2,"未出版社")],default=1)
        # 与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
    app01/models.py
    from django.contrib import admin
    from django.urls import path
    from stark.service.sites import site
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('stark/', site.urls),
    
    ]
    urls.py
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
    </head>
    <body>
    <h3>查看数据</h3>
    
    <div class="container">
       <div class="row">
           <table class="table table-striped">
        <thead>
             <tr>
                 {% for item in header_list %}
                    <th>{{ item }}</th>
                  {% endfor %}
             </tr>
    
        </thead>
        <tbody>
              {% for item in new_data %}
              <tr>
                  {% for info in item %}
                  <td>{{ info }}</td>
                  {% endfor %}
              </tr>
              {% endfor %}
    
    
        </tbody>
    </table>
       </div>
    </div>
    
    </body>
    
    </html>
    stark/templates/stark/list_view.html
    # -*- coding: utf-8 -*-
    # @Time    : 2019/4/12 11:48
    # @Author  : xxx
    # @Email   : xxx@admin.com
    # @File    : stark.py
    # @Software: PyCharm
    print("234")
    app02/stark.py

    全代码02版 增删改查  ModelForm

    # -*- coding: utf-8 -*-
    # @Time    : 2019/4/12 11:51
    # @Author  : xxx
    # @Email   : xxx@admin.com
    # @File    : sites.py
    # @Software: PyCharm
    from django.urls import path,re_path
    from django.shortcuts import HttpResponse,render,redirect
    from app01.models import *
    from django.utils.safestring import mark_safe
    from django.core.exceptions import FieldDoesNotExist
    from django.urls import reverse
    
    
    
    class ModelStark(object):
        '''
        默认配置类
        '''
        list_display=("__str__",)
        list_display_links = []
        model_form_class=None
    
        def __init__(self,model):
            self.model=model
            self.model_name = self.model._meta.model_name
            self.app_label = self.model._meta.app_label
    
        # 反向解析当前访问表的增删改查URL
        def get_list_url(self):
            # 反向解析当前表的删除的URL
            list_url = reverse("%s_%s_list" % (self.app_label, self.model_name))
            return list_url
    
        def get_add_url(self):
            # 反向解析当前表的删除的URL
            add_url = reverse("%s_%s_add" % (self.app_label, self.model_name))
            return add_url
    
        def get_delete_url(self,obj):
            # 反向解析当前表的删除的URL
            delete_url = reverse("%s_%s_delete" % (self.app_label, self.model_name), args=(obj.pk,))
            return delete_url
    
        def get_change_url(self, obj):
            # 反向解析当前表的删除的URL
            change_url = reverse("%s_%s_change" % (self.app_label, self.model_name), args=(obj.pk,))
            return change_url
    
        # 三个默认列
        def show_checkbox(self, obj=None, header=False):
            if header:
                return mark_safe("<input type='checkbox'>")
            return mark_safe("<input type='checkbox'>")
    
        def show_delbtn(self, obj=None, header=False):
            if header:
                return "删除"
    
            return mark_safe("<a href='%s'>删除</a>"%self.get_delete_url(obj))
    
        def show_editbtn(self, obj=None, header=False):
            if header:
                return "编辑"
            return mark_safe("<a href='%s'>编辑</a>" %self.get_change_url(obj))
    
        #  构建新的list_display
    
        def get_new_list_display(self):
            temp=[]
            temp.extend(self.list_display)
            temp.append(ModelStark.show_editbtn)
            temp.append(ModelStark.show_delbtn)
            temp.insert(0,ModelStark.show_checkbox)
    
            return temp
    
        #  视图函数
        def list_view(self,request):
            '''
            self: 当前访问模型表对应的配置类对象
            self.model: 当前访问模型表
            :param request:
            :return:
            '''
    
            queryset=self.model.objects.all()
            print(queryset)
            print(self.list_display) # ["title","price"]
    
            #   构建表头
    
            header_list=[]
            for field_or_func in self.get_new_list_display():
                if callable(field_or_func):
                    val=field_or_func(self,header=True)
                    header_list.append(val)
                    #header_list.append(field_or_func.__name__)
                else:
                     if field_or_func=="__str__":
                         val=self.model._meta.model_name.upper()
                         print(val)
                     else:
                          field_obj = self.model._meta.get_field(field_or_func)
                          val=field_obj.verbose_name
                     header_list.append(val)
    
            #  构建展示数据
            new_data=[]
            for obj in queryset:
                temp=[]
    
                for field_or_func in self.get_new_list_display(): # ["title","price","state","publish",show_authors]
                    if callable(field_or_func):
                        #  field:方法
                        val=field_or_func(self,obj)
                    else:
                        try:
                            #  field:字符串
                            from django.db.models.fields.related import ManyToManyField
                            field_obj=self.model._meta.get_field(field_or_func)
                            #  判断是否多对多字段
                            if type(field_obj)==ManyToManyField:
                                raise Exception("list_display不能是多对多字段!")
                            #  判断字段是否 拥有choices属性
                            if field_obj.choices:
                                val=getattr(obj,"get_%s_display"%field_or_func)()
                            else:
                                val=getattr(obj,field_or_func)
                                if field_or_func in  self.list_display_links:
                                    val=mark_safe("<a href='%s'>%s</a>"%(self.get_change_url(obj),val))
    
                        except FieldDoesNotExist as e:
                            #val=obj
                            val=getattr(obj,field_or_func)()
    
                    temp.append(val)
                new_data.append(temp)
    
    
            print("new_data",new_data) # [['python', Decimal('123.00')], ['java', Decimal('234.00')]]
    
    
            '''
            目标数据结构
            new_data=[
                ["python",123],
                ["java",234]
            ]
            '''
    
    
            #  相关变量
            table_name=self.model._meta.verbose_name
            add_url=self.get_add_url()
    
    
    
            return render(request,'stark/list_view.html',locals())
    
        def get_model_form(self):
            from django.forms import ModelForm
            class BaseModelForm(ModelForm):
                class Meta:
                    model = self.model
                    fields = "__all__"
    
            return self.model_form_class or BaseModelForm
    
        def add_view(self,request):
            BaseModelForm=self.get_model_form()
    
            if  request.method=="GET":
                form_obj=BaseModelForm()
                return render(request,"stark/add_view.html",locals())
            else:
                form_obj = BaseModelForm(request.POST)
                if form_obj.is_valid():
                    form_obj.save()
                    return redirect(self.get_list_url())
                else:
                    return render(request, "stark/add_view.html", locals())
    
        def change_view(self,request,id):
            BaseModelForm=self.get_model_form()
            edit_obj=self.model.objects.filter(pk=id).first()
            if  request.method=="GET":
                form_obj=BaseModelForm(instance=edit_obj)
                return render(request,"stark/change_view.html",locals())
            else:
                form_obj = BaseModelForm(request.POST,instance=edit_obj)
                if form_obj.is_valid():
                    form_obj.save()
                    return redirect(self.get_list_url())
                else:
                    return render(request, "stark/change_view.html", locals())
    
    
    
        def delete_view(self,request, id):
    
            if request.method=="POST":
                self.model.objects.filter(pk=id).delete()
                return redirect(self.get_list_url())
    
            list_url=self.get_list_url()
            return render(request,"stark/delete_view.html",locals())
    
        @property
        def get_urls(self):
    
            temp = [
                path("", self.list_view,name="%s_%s_list"%(self.app_label,self.model_name)),
                path("add/", self.add_view,name="%s_%s_add"%(self.app_label,self.model_name)),
                re_path("(d+)/change/", self.change_view,name="%s_%s_change"%(self.app_label,self.model_name)),
                re_path("(d+)/delete/", self.delete_view,name="%s_%s_delete"%(self.app_label,self.model_name)),
            ]
    
            return (temp, None, None)
    
    
    class StarkSite:
        '''
        stark全局类
        '''
        def __init__(self):
            self._registry = {}
    
        def register(self, model, admin_class=None, **options):
            admin_class = admin_class or ModelStark
            self._registry[model] = admin_class(model)
    
    
        def get_urls(self):
            #  动态为注册的模型类创建增删改查URL
            temp = []
            # {Book:ModelAdmin(Book),Publish:ModelAdmin(Publish)}
            for model, config_obj in self._registry.items():
                print("---->", model, config_obj)
                model_name = model._meta.model_name
                app_label = model._meta.app_label
                temp.append(
                    path("%s/%s/" % (app_label,model_name),config_obj.get_urls)
                )
    
            '''
               path("stark/app01/book",BookConfig(Book).list_view)
               path("stark/app01/book/add",BookConfig(Book).add_view)      
               path("stark/app01/publish",ModelAdmin(Publish).list_view)
               path("stark/app01/publish/add",ModelAdmin(Publish).add_view)
            
            '''
    
            return temp
    
        @property
        def urls(self):
            return self.get_urls(),None,None
    
    site = StarkSite()
    stark/service/sites.py
    # -*- coding: utf-8 -*-
    # @Time    : 2019/4/12 11:47
    # @Author  : xxx
    # @Email   : xxx@admin.com
    # @File    : stark.py
    # @Software: PyCharm
    
    from stark.service.sites import site,ModelStark
    from .models import *
    from django.utils.safestring import mark_safe
    from django.forms import ModelForm
    class BookModelForm(ModelForm):
        class Meta:
            model=Book
            fields="__all__"
            error_messages={
               "title":{ "required":" 该字段不能为空!"}
            }
    
    
    class BookConfig(ModelStark):
    
        def show_authors(self,obj=None,header=False):
            if header:
                return "作者信息"
            return " ".join([author.name for author in obj.authors.all()])
    
    
        list_display=["title","price","state","publish",show_authors]
        list_display_links=["title","price"]
    
        model_form_class=BookModelForm
    
    site.register(Book,BookConfig)
    site.register(Publish)
    print(site._registry)
    app01/stark.py
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
    </head>
    <body>
    <h3>查看数据</h3>
    
    <div class="container">
       <div class="row">
           <a href="{{ add_url }}" class="btn btn-primary">添加{{ table_name }}</a>
           <table class="table table-striped">
        <thead>
             <tr>
                 {% for item in header_list %}
                    <th>{{ item }}</th>
                  {% endfor %}
             </tr>
    
        </thead>
        <tbody>
              {% for item in new_data %}
              <tr>
                  {% for info in item %}
                  <td>{{ info }}</td>
                  {% endfor %}
              </tr>
              {% endfor %}
    
    
        </tbody>
    </table>
       </div>
    </div>
    
    </body>
    
    </html>
    stark/templates/stark/list_view.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
         <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
        <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;
            }
    
            .error{
                color: red;
            }
        </style>
    </head>
    <body>
    
    <h3> 添加数据</h3>
    {% include "stark/form.html" %}
    
    
    
    
    </body>
    </html>
    stark/templates/stark/add_view.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
         <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
        <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;
            }
    
            .error{
                color: red;
            }
        </style>
    </head>
    <body>
    <h3>编辑数据</h3>
    
    {% include "stark/form.html" %}
    
    </body>
    </html>
    stark/templates/stark/change_view.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
    
    </head>
    <body>
    
    <form action="" method="post">
         {% csrf_token %}
         <a href="{{ list_url }}" class="btn btn-warning">取消</a>
         <input class="btn btn-danger" type="submit" value="确认删除">
    </form>
    
    
    </body>
    </html>
    stark/templates/stark/delete_view.html
    <div class="container">
        <div class="row">
            <div class="col-md-8">
                <form action="" method="post" novalidate>
                    {% csrf_token %}
    
                    {% for field in form_obj %}
                       <div class="form-group">
                           <label for="">{{ field.label }}</label>
                           {{ field }}  <span class="error pull-right">{{ field.errors.0 }}</span>
                       </div>
                    {% endfor %}
    
                    <button class="btn btn-default">submit</button>
    
    
                </form>
            </div>
        </div>
    </div>
    stark/templates/stark/form.html

    全代码03版 增删改查  ModelForm 分页 筛选框

    # -*- coding: utf-8 -*-
    # @Time    : 2019/4/12 11:51
    # @Author  : xxx
    # @Email   : xxx@admin.com
    # @File    : sites.py
    # @Software: PyCharm
    from django.urls import path,re_path
    from django.shortcuts import HttpResponse,render,redirect
    from app01.models import *
    from django.utils.safestring import mark_safe
    from django.core.exceptions import FieldDoesNotExist
    from django.urls import reverse
    
    class ShowList(object):
        def __init__(self,request,config_obj,queryset):
            self.config_obj=config_obj  #当前模型配置类对象  eg:BookConfig(Book) 默认是ModelStark(Book)
            self.queryset=queryset #符合条件queryset字典数据记录
            self.request=request #请求
            self.pager_queryset=self.get_pager_queryset()  #类实例化时执行分页函数 获取当前页的数据
    
        def get_pager_queryset(self):
    
            from stark.utils.page import Pagination
            current_page = self.request.GET.get("page", 1)
            self.pagination = Pagination(self.request, current_page, self.queryset, per_page_num=self.config_obj.per_page_num or 5)
            # per_page_num=self.config_obj.per_page_num or 5 eg:模型配置类里面(BookConfig(Book))自定义下标个数 没有定义就用5
            queryset = self.queryset[self.pagination.start:self.pagination.end] #获取当前页的所有数据切片
    
            return queryset
    
        def get_header(self):
            '''
            获取表头
            :return:
            '''
            #   构建表头
    
            header_list = []
            for field_or_func in self.config_obj.get_new_list_display():
                if callable(field_or_func): #如果时可调用的函数
                    val = field_or_func(self.config_obj, header=True)  #eg: def show_delbtn(self,obj=None, header=False):pass  ---self =self.config_obj,obj=None,header=True
                    header_list.append(val)
                    # header_list.append(field_or_func.__name__)
                else:
                    if field_or_func == "__str__":  #如果没有自定义list_display  则默认只有三个函数列  +
                        val = self.config_obj.model._meta.model_name.upper() #eg:BookConfig(Book).Book._meta.model_name.upper() = 'book'.upper()
                        print(val)
                    else:
                        field_obj = self.config_obj.model._meta.get_field(field_or_func)  #得到模型类的每个字段类的实例对象
                        val = field_obj.verbose_name #当field_obj有verbose_name属性时则用verbose_name ,无则用字段类的实例对象名(字段名) eg:price、state、publish
                    header_list.append(val)
    
            return header_list
    
        def get_body(self):
            '''
            获取标体
            :return:
            '''
            #  构建展示数据
            new_data = []
            for obj in self.pager_queryset:
                temp = []
    
                for field_or_func in self.config_obj.get_new_list_display():  # ["title","price","state","publish",show_authors]
                    if callable(field_or_func):
                        #  field:方法
                        val = field_or_func(self.config_obj, obj)  #obj为queryset字段的对象
                    else:
                        try:
                            #  field:字符串
                            from django.db.models.fields.related import ManyToManyField
                            field_obj = self.config_obj.model._meta.get_field(field_or_func)
                            #  判断是否多对多字段
                            if type(field_obj) == ManyToManyField:
                                raise Exception("list_display不能是多对多字段!")
                            #  判断字段是否 拥有choices属性
                            if field_obj.choices:
                                val = getattr(obj, "get_%s_display" % field_or_func)()  #模型类(有一个eg:get_state_display(self)方法来处理拥有choices属性的字段)实例对象
                            else:
                                val = getattr(obj, field_or_func)
                                if field_or_func in self.config_obj.list_display_links:  #模型配置类自定义list_display_links  #可以链接到编辑页面
                                    val = mark_safe("<a href='%s'>%s</a>" % (self.config_obj.get_change_url(obj), val))
    
                        except FieldDoesNotExist as e:
                            # val=obj
                            val = getattr(obj, field_or_func)()
    
                    temp.append(val)
                new_data.append(temp)
    
            print("new_data", new_data)
    
            '''
            new_data [["<input type='checkbox'>", "<a href='/stark/app01/book/1/change/'>python180</a>", "<a href='/stark/app01/book/1/change/'>123.00</a>", '已出版', <Publish: 苹果出版设>, 'alex egon', "<a href='/stark/app01/book/1/change/'>编辑</a>", "<a href='/stark/app01/book/1/delete/'>删除</a>"], 
            ["<input type='checkbox'>", "<a href='/stark/app01/book/2/change/'>java</a>", "<a href='/stark/app01/book/2/change/'>234.00</a>", '已出版', <Publish: 橘子出版设>, 'egon', "<a href='/stark/app01/book/2/change/'>编辑</a>", "<a href='/stark/app01/book/2/delete/'>删除</a>"],
             ["<input type='checkbox'>", "<a href='/stark/app01/book/4/change/'>挤奶龙爪手123</a>", "<a href='/stark/app01/book/4/change/'>180.00</a>", '已出版', <Publish: 苹果出版设>, 'egon', "<a href='/stark/app01/book/4/change/'>编辑</a>", "<a href='/stark/app01/book/4/delete/'>删除</a>"]]
            目标数据结构
            new_data=[
                ["python",123],
                ["java",234]
            ]
            '''
    
            return new_data
    
    class ModelStark(object):
        '''
        默认配置类
        '''
        list_display=("__str__",)  # 自定义显示哪些字段
        list_display_links = []  #自定义 哪些字段 可以链接编辑
        model_form_class=None #自定义model form模型表单类
        per_page_num=None #分页 自定义每页显示的数据记录条数
        search_fields=[] #自定义可以筛选框可以采用哪些值筛选
        search_val=None #用户输入的筛选框的值
    
        def __init__(self,model):
            self.model=model  # 模型类 eg: Book、Publish等
    
            # self.model._meta 默认生成的表名 应用名.模型类名小写 eg:   app01.book
            self.model_name = self.model._meta.model_name#    self.model._meta.model_name <---->Book._meta.model_name <------>模型类名小写 book
            self.app_label = self.model._meta.app_label#app名 eg: self.model._meta.app_label = app01
    
        # 反向解析当前访问表的增删改查URL
        def get_list_url(self):
            # 反向解析当前表的删除的URL
            list_url = reverse("%s_%s_list" % (self.app_label, self.model_name))
            return list_url
    
        def get_add_url(self):
            # 反向解析当前表的删除的URL
            add_url = reverse("%s_%s_add" % (self.app_label, self.model_name))
            return add_url
    
        def get_delete_url(self,obj):
            # 反向解析当前表的删除的URL
            delete_url = reverse("%s_%s_delete" % (self.app_label, self.model_name), args=(obj.pk,))
            return delete_url
    
        def get_change_url(self, obj):
            # 反向解析当前表的删除的URL
            change_url = reverse("%s_%s_change" % (self.app_label, self.model_name), args=(obj.pk,))
            return change_url
    
        # 三个默认列
        def show_checkbox(self, obj=None, header=False):
            if header:
                return mark_safe("<input type='checkbox'>")  #将字符串转换成前端html标签
            return mark_safe("<input type='checkbox'>")
    
        def show_delbtn(self, obj=None, header=False):
            if header:
                return "删除"
    
            return mark_safe("<a href='%s'>删除</a>"%self.get_delete_url(obj))
    
        def show_editbtn(self, obj=None, header=False):
            if header:
                return "编辑"
            return mark_safe("<a href='%s'>编辑</a>" %self.get_change_url(obj))
    
        #  构建新的list_display
    
        def get_new_list_display(self):
            temp=[]
            temp.extend(self.list_display)#迭代对象循环添加进去
            temp.append(ModelStark.show_editbtn) #编辑按钮
            temp.append(ModelStark.show_delbtn) #删除按钮
            temp.insert(0,ModelStark.show_checkbox) #复选框
    
            return temp
    
        def get_search_condition(self,val):
            # val = request.GET.get("q")  #获取前端页面搜索框里面 name为q的values
            # print(val)
    
            from django.db.models import Q
            q = Q()
            # if val:  #如果用户在搜索框 输入值
            self.search_val = val
            q.connector = "or"  #实现或操作  并
            for field in self.search_fields:  # ["title","price"] #在app01/stark.py可以自定义 搜索的数据库的字段
                print(field)
                # queryset=queryset.filter(Q(title__contains=val)|Q(price__contains=val))
                q.children.append((field + "__contains", val))#把条件追加进去
            # else:
            #     self.search_val=None
            #     # print(q) #(AND: )  没有用户搜索值时
    
            return q  #把搜索条件返回 eg:   相当于 q = Q(title__contains=val)|Q(price__contains=val)
    
    
    
    
        #  视图函数 查
        def list_view(self,request):
            '''
            self: 当前访问模型表对应的配置类对象
            self.model: 当前访问模型表
            :param request:
            :return:
            '''
            queryset=self.model.objects.all()  #获取
    
            # search过滤
            val = request.GET.get("q")
            if val:  #判断是有筛选框传值
                queryset=queryset.filter(self.get_search_condition(val)) #调用过滤类方法 传值request
            else:
                self.search_val = None  #将上次筛选框的值清空
    
            show_list=ShowList(request,self,queryset)  #self  eg: BookConfig(ModelStark)实例对象
    
            #  相关变量
            table_name=self.model._meta.verbose_name  #模型表 verbose_name 注释
            add_url=self.get_add_url() #获取添加数据的urls
    
            return render(request,'stark/list_view.html',locals())
    
    
    
    #判断app01/stark.py是否有传了model_form_class(自定义模型表单类) 没有就使用BaseModelForm  用在增、改两个视图
        def get_model_form(self):
            from django.forms import ModelForm
            class BaseModelForm(ModelForm):
                class Meta:
                    model = self.model
                    fields = "__all__"
    
            return self.model_form_class or BaseModelForm
    
        #  视图函数 增
        def add_view(self,request):
            BaseModelForm=self.get_model_form()
    
            if  request.method=="GET":
                form_obj=BaseModelForm()
                return render(request,"stark/add_view.html",locals())
            else:
                form_obj = BaseModelForm(request.POST)
                if form_obj.is_valid():
                    form_obj.save()
                    return redirect(self.get_list_url())
                else:
                    return render(request, "stark/add_view.html", locals())
    
        #  视图函数 改
        def change_view(self,request,id):
            BaseModelForm=self.get_model_form()
            edit_obj=self.model.objects.filter(pk=id).first()
            if  request.method=="GET":
                form_obj=BaseModelForm(instance=edit_obj)
                return render(request,"stark/change_view.html",locals())
            else:
                form_obj = BaseModelForm(request.POST,instance=edit_obj)
                if form_obj.is_valid():
                    form_obj.save()
                    return redirect(self.get_list_url())
                else:
                    return render(request, "stark/change_view.html", locals())
    
        #  视图函数 删
        def delete_view(self,request, id):
    
            if request.method=="POST":
                self.model.objects.filter(pk=id).delete()
                return redirect(self.get_list_url())
    
            list_url=self.get_list_url()
            return render(request,"stark/delete_view.html",locals())
    
    
    
        @property
        def get_urls(self):
    
            temp = [
                path("", self.list_view,name="%s_%s_list"%(self.app_label,self.model_name)),
                path("add/", self.add_view,name="%s_%s_add"%(self.app_label,self.model_name)),
                re_path("(d+)/change/", self.change_view,name="%s_%s_change"%(self.app_label,self.model_name)),
                re_path("(d+)/delete/", self.delete_view,name="%s_%s_delete"%(self.app_label,self.model_name)),
            ]
    
            return (temp, None, None)
    
    
    
    class StarkSite:
        '''
        stark全局类
        '''
        def __init__(self):
            self._registry = {}
    
        def register(self, model, admin_class=None, **options):
            admin_class = admin_class or ModelStark
            self._registry[model] = admin_class(model)
    
    
        def get_urls(self):
            #  动态为注册的模型类创建增删改查URL
            temp = []
            # {Book:ModelAdmin(Book),Publish:ModelAdmin(Publish)}
            for model, config_obj in self._registry.items():
                print("---->", model, config_obj)
                model_name = model._meta.model_name
                app_label = model._meta.app_label
                temp.append(
                    path("%s/%s/" % (app_label,model_name),config_obj.get_urls)
                )
    
            '''
               path("stark/app01/book",BookConfig(Book).list_view)
               path("stark/app01/book/add",BookConfig(Book).add_view)      
               path("stark/app01/publish",ModelAdmin(Publish).list_view)
               path("stark/app01/publish/add",ModelAdmin(Publish).add_view)
            
            '''
    
            return temp
    
        @property
        def urls(self):
            return self.get_urls(),None,None
    
    site = StarkSite()
    stark/service/sites.py
    # -*- coding: utf-8 -*-
    # @Time    : 2019/4/12 11:47
    # @Author  : xxx
    # @Email   : xxx@admin.com
    # @File    : stark.py
    # @Software: PyCharm
    
    from stark.service.sites import site,ModelStark
    from .models import *
    from django.utils.safestring import mark_safe
    from django.forms import ModelForm
    
    
    #自定义模型表单类
    class BookModelForm(ModelForm):
        class Meta:
            model=Book
            fields="__all__"
            error_messages={
               "title":{ "required":" 该字段不能为空!"}
            }
    
    
    #自定义模型配置类
    class BookConfig(ModelStark):
            #自定义函数列
        def show_authors(self,obj=None,header=False):
            if header:
                return "作者信息"
            return " ".join([author.name for author in obj.authors.all()])
    
    #自定义显示字段
        list_display=["title","price","state","publish",show_authors]
    #自定义链接字段
        list_display_links=["title","price"]
    #自定义模型表单类的值传给 模型配置类实例对象
        model_form_class=BookModelForm
    # 自定义分页 :每页显示的数据条数
        per_page_num=3
     # 自定义筛选字段
        search_fields=["title","price"]
    
    #注册模型类
    site.register(Book,BookConfig)
    site.register(Publish)
    # print(site._registry)
    app01/stark.py
    from django.contrib import admin
    from django.urls import path
    from stark.service.sites import site
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('stark/', site.urls),
    
    ]
    urls.py
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
    </head>
    <body>
    <h3>查看数据</h3>
    
    <div class="container">
    
       <div class="row">
    
           <div class="panel panel-info">
          <div class="panel-heading">
            <h3 class="panel-title"></h3>
          </div>
          <div class="panel-body">
            <a href="{{ add_url }}" class="btn btn-primary">添加{{ table_name }}</a>
              {% if show_list.config_obj.search_fields %} {# 注释:如果模型配置类里面没有配置search_fields,就不显示搜索框 #}
                  <form action="" method="get">
                      <div class="input-group pull-right" style=" 400px">
                          <input value="{{ show_list.config_obj.search_val|default:'' }}" type="text" name="q" class="form-control" placeholder="Search for...">
                          <span class="input-group-btn">
                            <button class="btn btn-default">Search!</button>
    
                          </span>
                        </div>
                  </form>
              {% endif %}
    
          </div>
        </div>
    
    
           <table class="table table-striped">
                <thead>
                     <tr>
                         {% for item in show_list.get_header %}
                            <th>{{ item }}</th>
                          {% endfor %}
                     </tr>
    
                </thead>
                <tbody>
                      {% for item in show_list.get_body %}
                      <tr>
                          {% for info in item %}
                          <td>{{ info }}</td>
                          {% endfor %}
                      </tr>
                      {% endfor %}
    
    
                </tbody>
           </table>
    
           <div class="pull-right">
               {{ show_list.pagination.page_html|safe }}
           </div>
    
       </div>
    </div>
    
    </body>
    
    </html>
    stark/templates/stark/list_view.html
    class Pagination(object):
    
        def __init__(self, request, current_page, all_data, per_page_num=None, max_page_count=11):
            """
            封装分页相关数据
            :param current_page: 当前页
            :param all_count:    分页数据中的数据总条数
            :param per_page_num: 每页显示的数据条数
            :param max_page_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 = len(all_data)
            self.per_page_num = per_page_num
    
            # 总页码
            all_pager, tmp = divmod(self.all_count, per_page_num)
            if tmp:
                all_pager += 1
            self.all_pager = all_pager
            self.max_page_count = max_page_count
            self.max_page_count_half = int((max_page_count - 1) / 2)
    
            self.request = request
    
            #
            import copy
            self.params = copy.deepcopy(self.request.GET)
    
        '''
         all_count=100    per_page_num =10 
    
         current_page        start    end
              1                 0      10
              2                 10     20
              3                 20     30
    
    
          all_count=100    per_page_num =8
    
         current_page        start    end
              1                 0      8
              2                 8      16
              3                 16     24  
    
         表达式:    start= (current_page-1)*per_page_num    end =current_page* per_page_num
    
        '''
    
        @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.max_page_count:
                pageRange = range(1, self.all_pager + 1)
            # 总页码  > 11
            else:
                # 当前页如果小于页面上最多显示(11-1)/2个页码
                if self.current_page <= self.max_page_count_half:
                    pageRange = range(1, self.max_page_count + 1)
                # 当前页大于5
                else:
                    # 页码翻到最后
                    if (self.current_page + self.max_page_count_half) > self.all_pager:
                        pageRange = range(self.all_pager - self.max_page_count + 1, self.all_pager + 1)
                    else:
                        pageRange = range(self.current_page - self.max_page_count_half,
                                          self.current_page + self.max_page_count_half + 1)
    
            # 构建分页页码的html
            page_html_list = []
            self.params["page"] = 1
            first_page = '<nav aria-label="Page navigation"><ul class="pagination"><li><a href="?%s">首页</a></li>' % (
            self.params.urlencode(),)
            page_html_list.append(first_page)
            self.params["page"] = self.current_page - 1
            if self.current_page <= 1:
                prev_page = '<li class="disabled"><a href="#">上一页</a></li>'
            else:
                prev_page = '<li><a href="?%s">上一页</a></li>' % (self.params.urlencode(),)
    
            page_html_list.append(prev_page)
            # self.params: ["page":9,"a":1,"b":2]
            for i in pageRange:
                self.params["page"] = i
                if i == self.current_page:
                    temp = '<li class="active"><a href="?%s">%s</a></li>' % (self.params.urlencode(), i,)
                else:
                    temp = '<li><a href="?%s">%s</a></li>' % (self.params.urlencode(), i,)
                page_html_list.append(temp)
    
            self.params["page"] = self.current_page + 1
            if self.current_page >= self.all_pager:
                next_page = '<li class="disabled"><a href="#">下一页</a></li>'
            else:
                next_page = '<li><a href="?%s">下一页</a></li>' % (self.params.urlencode(),)
            page_html_list.append(next_page)
    
            self.params["page"] = self.all_pager
            last_page = '<li><a href="?%s">尾页</a></li> </ul></nav>' % (self.params.urlencode())
            page_html_list.append(last_page)
    
            return ''.join(page_html_list)
    stark/utils/page.py
  • 相关阅读:
    css实现并列效果
    去除inline-block之间的间距
    鼠标点击<input>输入域后出现有颜色的边框
    消除a标签点击后产生的虚线框
    超过既定行数时,用省略号代替的方法
    常用按钮样式
    常用颜色
    通过Gulp流方式处理流程
    IntelliJ IDEA 10 配置 Tomcat7
    chrome浏览器调试线上文件映射本地文件
  • 原文地址:https://www.cnblogs.com/linux985/p/11101121.html
Copyright © 2011-2022 走看看