zoukankan      html  css  js  c++  java
  • day062 Django之CRM项目admin组件

    本节内容:

    1、admin组件使用
    2、admin源码解析
    

    学习组件的三部曲:

    1、学习如何使用组件
    2、阅读源码
    3、写一个类似的组件
    

    一、admin组件使用

    admin是一个Django封装好的app而已
    
    Django 提供了基于 web 的管理工具。
    
    Django 自动管理工具是 django.contrib 的一部分。
    

    1、admin配置的增删改查的url:

    查:http://127.0.0.1:8000/admin/app01/publish/
    增:http://127.0.0.1:8000/admin/app01/publish/add/
    改:http://127.0.0.1:8000/admin/app01/publish/1/change/
    删:http://127.0.0.1:8000/admin/app01/publish/1/delete/
    
    url这里通过不同的app名称来具体找对应的表
    

    2、使用前的工作

    1、配置settings.py中的INSTALLED_APPS路径

    这里配置好,Django才找得到你的APP
    
    # Application definition
    
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        "app01" # 写法一:
        'app01.apps.App01Config'  # 写法二
    ]
    django.contrib是一套庞大的功能集,它是Django基本代码的组成部分。
    
    Python

    2、激活管理工具

    通常我们在生成项目时会在 urls.py 中自动设置好,
    
    from django.contrib import admin
    from django.urls import path
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        ]
    
    Python

    3、使用管理工具

    启动开发服务器,然后在浏览器中访问 http://127.0.0.1:8000/admin/,得到登陆界面,
    你可以通过命令 python manage.py createsuperuser 在Terminal控制台下来创建超级用户。
    

    4、先在数据库中创建好数据表的结构

    本节实例中的models.py文件

    from django.db import models
    
    # Create your models here.
    from django.db import models
    
    # Create your models here.
    class Book(models.Model):
        title = models.CharField( max_length=32)
        pub_date=models.DateField()
        price=models.DecimalField(max_digits=5,decimal_places=2)
        publish=models.ForeignKey(to="Publish",to_field="id",on_delete=models.CASCADE,null=True)
        authors=models.ManyToManyField("Author",db_table="book2authors") # 创建关系表
        def __str__(self):
            return self.title
    
    class Publish(models.Model):
        name=models.CharField( max_length=32)
        city=models.CharField( max_length=32)
        email=models.CharField(max_length=32)
        def __str__(self):
            return self.name
    
    class Author(models.Model):
        name=models.CharField( max_length=32)
        age=models.IntegerField()
        #books=models.ManyToManyField("Book")
        ad=models.OneToOneField("AuthorDetail",null=True,on_delete=models.CASCADE)
        def __str__(self):
            return self.name
    class AuthorDetail(models.Model):
        birthday=models.DateField()
        telephone=models.BigIntegerField()
        addr=models.CharField( max_length=64)
        # author=models.OneToOneField("Author",on_delete=models.CASCADE)
        def __str__(self):
            return str(self.telephone)
    
    Python

    3、admin的定制

    完成了上面的操作,就可以开始我们的使用admin组件了。
    为了让 admin 界面管理某个数据模型,我们需要先注册该数据模型到 admin
    

    1、两种注册方法

    在admin.py中只需要讲Mode中的某个类注册,即可在Admin中实现增删改查的功能,如:
    
    admin.site.register(models.UserInfo)
    但是,这种方式比较简单,
    
    
    如果想要进行更多的定制操作,需要利用ModelAdmin进行操作,如:
    
    方式一:
        class UserAdmin(admin.ModelAdmin):
            list_display = ('user', 'pwd',)
    
        admin.site.register(models.UserInfo, UserAdmin) # 第一个参数可以是列表
    
    
    方式二:
        @admin.register(models.UserInfo)     # 第一个参数可以是列表
        class UserAdmin(admin.ModelAdmin):
            list_display = ('user', 'pwd',)
    
    Python

    2、admin具体的定制方法实例

    本节实例中的对应app01程序admin.py文件代码

    from django.contrib import admin
    
    # Register your models here.
    from .models import Book
    from .models import Publish
    from .models import Author
    from .models import AuthorDetail
    
    
    print("app01 admin.py>>>>")  # 启动项目的时候会自动加载admin.py文件
    
    class PublishConfig(admin.ModelAdmin):
        list_display=["name","city","email"]
    
    class BookConfig(admin.ModelAdmin):
    
        def show_authors(self,obj): # <QuerySet [<Author: 横斜>]> 拿到Authors对象(queryset对象集合,因为可能有多个作者)
            print(obj.authors.all())  # 这里obj是实例化的book对象
            return ",".join([obj.name for obj in obj.authors.all()]) # 用join来分隔作者,列表推导式拿到每一个作者的名字
    
        list_display =  ["title","price","publish","pub_date","show_authors"] # 多对一没问题还可以正常些字段就显示,多对多就要用方法来显示
        list_display_links = ["price","publish"]  # 设置点击可以进入编辑的锚点字段(类似于a标签跳转编辑)。
    
        list_filter = ["publish","authors"] # 筛选框,一般根据多对多,多对一的字段进行筛选
        search_fields = ["title","price"]  # 搜索框的内容根据在列表中字段进行搜索
    
        list_editable = ["title",] # 直接在显示页面可以编辑列表中的字段
        # change_list_template="mylist.html" # 显示自己的页面,这样根本就没有用到admin提供的,没什么用
        ordering = ["-price"] # 根据该条件进行排序显示,-price根据价格降序排列
    
        # 批量修改的功能三步走
        def patch_init(self,request,queryset): # 第一步定义方法
            queryset.update(price=100)
    
        patch_init.short_description = "批量初始化" # 第二:起名,在action中显示该操作的名字
    
        actions = [patch_init,]  # 第三:把这个功能添加进action里,点击就会执行该方法
    
    
    
    admin.site.register(Book,BookConfig) # register是site对象的一个方法,拿到的是一个字典
    admin.site.register(Publish,PublishConfig)
    admin.site.register(Author) # 简单的注册,不能进行更多的定制操作
    admin.site.register(AuthorDetail)
    
    print("app01:>>>>>",admin.site._registry) # 拿到该对象下的字典存放着创建的表,大家共享的单例模式下的字典
    
    Python

    二、admin源码解析

    在看源码解析之前,首先我们要知道单例模式是什么???
    

    1、单例模式

    单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。
    当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。
    
    比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息。
    如果在程序运行期间,有很多地方都需要使用配置文件的内容,
    也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,
    而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。
    
    事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象。
    

    1、在python中,实现单例模式的四种方法

    1、使用模块
    2、使用 __new__
    3、使用装饰器(decorator)
    4、使用元类(metaclass)
    

    2、常用的两种实现单例模式的方法new和使用模块

    1)使用 __new__
    为了使类只能出现一个实例,我们可以使用 __new__ 来控制实例的创建过程,代码如下:
    
    class Singleton(object):
        _instance = None
        def __new__(cls, *args, **kw):
            if not cls._instance:
                cls._instance = super(Singleton, cls).__new__(cls, *args, **kw)
            return cls._instance
    
    class MyClass(Singleton):
        a = 1
    
    在上面的代码中,我们将类的实例和一个类变量 _instance 关联起来,
    如果 cls._instance 为 None 则创建实例,否则直接返回 cls._instance。
    
    执行情况如下:
    
    
    >>> one = MyClass()
    >>> two = MyClass()
    >>> one == two
    True
    >>> one is two
    True
    >>> id(one), id(two)
    (4303862608, 4303862608)
    
    
    (2)使用模块
    
    其实,Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,
    当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。
    因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。
    
    如果我们真的想要一个单例类,可以考虑这样做:
    
    # mysingleton.py
    class My_Singleton(object):
        def foo(self):
            pass
    
    my_singleton = My_Singleton()
    将上面的代码保存在文件 mysingleton.py 中,然后这样使用:
    
    from mysingleton import my_singleton
    
    my_singleton.foo()
    
    Python

    2、admin执行流程(三步走)

    1、启动所有app下的admin.py文件

    启动Django项目的时候就会,循环加载执行所有已经注册的app中的admin.py文件
    
    # 源码中会自动执行该方法:
    def autodiscover():
        autodiscover_modules('admin', register_to=site)
    
    Python

    2、注册模型类

    admin.site: AdminSite的单例对象
    admin.site.register(Book,BookConfig) # 注册
    admin.site.register(Author)
    
    class ModelAdmin():
          pass
    
    class AdminSite():  # 所有的app共用这个单例对象,
    
        def __init__():
            self._registry = {}  # model_class class -> admin_class instance 模型类为键,配置类的实例对象为值
    
    
        def register(self, model_or_iterable, admin_class=None): # 这个方法主要干了两件事,
            admin_class = admin_class or ModelAdmin   # 看你参数是否有传配置类,有就用你传的,没有就默认的
            self._registry[model] = admin_class(model, self)  # 往这个单例对象的实例变量,添加一个键值对
                                                            # model_class class -> admin_class instance
    
    Python

    3、基于二级分发设计url路由

    语法:
    path('shuying/',([ ],None,None)),
    
    补充知识点:
    Book._meta.model_name  # 拿到当前表的小写表名 'book'
    Book._meta.app_label  # 拿到当前表所在的app名称 'app01'
    

    一二级分发的简单示例url.py文件

    # 这里就没有分开解耦了直接写在同一个页面方便查看
    from django.contrib import admin
    from django.urls import path
    
    from django.shortcuts import HttpResponse
    
    def test01(request):
        return HttpResponse("test01>>>>>>>")
    def test02(request):
        return HttpResponse("test02>>>>>>>")
    def test03(request):
        return HttpResponse("test03>>>>>>>")
    def test04(request):
        return HttpResponse("test04>>>>>>>")
    def test05(request):
        return HttpResponse("test05>>>>>>>")
    
    urlpatterns = [
        # # 一级分发
        # path("index/",([
        #            path('test01/',test01), # 语法是:固定嵌套
        #            path('test02/',test02),
        #                ],None,None)),
        #
        # # 二级分发
        # path("index/",([
        #            path('name/',([
        #                path('alex/',test01),
        #                path('egon/',test02)
        #            ],None,None)), # 语法是:固定嵌套
        #            path('shop/',([
        #                path('apple/',test03),
        #                path('huawei/',test04),
        #                path('chang/',test05)
        #            ],None,None)),
        #                ],None,None)),
    ]
    
    Python

    本节示例二级分发的应用

    from django.contrib import admin
    from django.urls import path,re_path
    
    from django.shortcuts import HttpResponse
    
     # 二级分发应用
    
    def add_view(request):
        return HttpResponse("add_view...")
    def list_view(request):
        return HttpResponse("list_view...")
    def change_view(request,id):
        return HttpResponse("change_view...")
    def delete_view(request,id):
        return HttpResponse("delete_view...")
    
    
     # 二级分发
    def get_urls2():
        temp=[
            path('',list_view),
            path('add/',add_view),
            re_path('(d+)/change/',change_view), # 这里写对应url下执行的视图函数
            re_path('(d+)/delete/',delete_view)
        ]
        return temp # 记得返回一个列表
    
    # 一级分发
    def get_urls():
        print("查看对象>>>>>>>",admin.site._registry)  #{Book:BookCongfigObj,Publish:PublishConfigObj,.....}
                                                      # 拿到site对象中的_register字典
        temp = []
        for model,config_obj in admin.site._registry.items():
            model_name = model._meta.model_name  # 拿到该对象的小写表名
            app_label = model._meta.app_label  # 查找当前表格对象的在哪个app下,拿到该APP名称
            temp.append(path('%s/%s/' %(app_label,model_name),(get_urls2(),None,None)))
        return temp
    
    urlpatterns = [
        # path('admin/', admin.site.urls),
    
        # 二级分发应用
        path('shuying/',(get_urls(),None,None)),
    ]
    
    
    Python

  • 相关阅读:
    [已解决] Python logging 重复打印日志信息
    scrapy
    Python 元编程
    MySQL性能优化 分区
    SQL Mode
    Golang 接口
    Python partial
    栈、队列(链表实现)
    Golang 位向量
    Java50题——学习以及思考
  • 原文地址:https://www.cnblogs.com/yipianshuying/p/10278471.html
Copyright © 2011-2022 走看看