• django之admin管理工具


    admin组件的使用

      Django 提供了基于 web 的管理工具。

      Django 自动管理工具是 django.contrib 的一部分。你可以在项目的 settings.py 中的 INSTALLED_APPS 看到它:

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'app01.apps.App01Config',
        'app02.apps.App02Config'
      'app02' #这样也可以,就是不规范
         ] 注意:如果是用IDE工具建立项目时,第一个应用会把你注册进去,    如果是用 python manage.py startapp app02创建的应用,他并不会帮你把应用帮你注册进去,所以你要自己手动到settinngs把应用注册admin

    admin工具激活

      通常我们在生成项目时会在 urls.py 中自动设置好,

    from django.contrib import admin
    from django.urls import path
    
    urlpatterns = [
        path('admin/', admin.site.urls),

      这样就可以运行项目(其实只要创建项目,应用注册完,直接启动项目,并访问127.0.0.1:8000/admin就能看到首页)

       注:我这是有导入相应的模型的截图

    使用工具

      启动开发服务器,然后在浏览器中访问 http://127.0.0.1:8000/admin/,得到登陆界面,你可以通过命令 python manage.py createsuperuser(username='xxx',password='xxxx') 来创建超级用户。

      为了让 admin 界面管理某个数据模型,我们需要先注册该数据模型到 admin.

    1. 首先要有模型类  models.py

    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)

    2. 在admin中引入模型类 admin.py

    from django.contrib import admin
    from .models import Publish, Book, Author, AuthorDetail #从模型类导入模型到admin # Register your models here.


    #把导入过来的模型类,用注册到admin,就可以实现通过admin增删改查
    admin.site.register(Book)
    admin.site.register(AuthorDetail)
    admin.site.register(Author)
    admin.site.register(Publish)

    admin之定制工具

      简单的admin注册完就可以实现增删改查的功能,但是,要想做一些复杂的功能就需要自己去定制工具了

    方式一:
    class PublishConfig(admin.ModelAdmin):
    list_display = ['name','email','city']
    admin.site.register(Publish)   # 第一个参数可以是列表


    方式二:
    @admin.siteregister(Publish)
    class PublishConfig(admin.ModelAdmin):
        list_display = ['name','email','city']    # 第一个参数可以是列表

    django会帮你创建:

      增删改查的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/

     model.Aamin提供了大量可定制功能

    1. list_display   #定制列表的表头,就是一张表中要显示那些字段

    2.list_display_link #指定显示的那些字段为超链接,可点击跳转到编辑页面

    3.list_filter #指定按那些字段进行筛选(定制右侧快速筛选)

    4. list_editable #列表时,可以编辑的列(可编辑的列指可在当前页面直接编辑,不需要跳转到编辑页,可编辑列会编程一个编辑框)
        
      5. search_fields   #列表时,模糊搜索的功能(定制搜索框并提供模糊搜索字段)

    6. action #列表时,定制action中的操作(批量操作)

    7. ordering #列表时,数据排序规则,默认升序

      看一下应用:  admin.py

    from django.contrib import admin
    from .models import Publish, Book, Author, AuthorDetail
    # Register your models here.
    
    #自定义模型类,要继承admin.ModelAdmin并且在register的时候要写进去才有效
    class BookConfig(admin.ModelAdmin):
    
        #显示作者(多对多的关系)
        def show_authors(self, obj):
            print(obj.authors.all())
            return ",".join([obj.name for obj in obj.authors.all()])
    
        #批量初始化
        def patch_init(self,request,queryset):
            queryset.update(price=100)
        patch_init.short_description = '批量初始化'
        actions = [patch_init,]
                                               #这边要注意,show_authors是函数,单这边用字符串,这是1版本和2版本的差别
        list_display = ['title','price','publish','pub_date','show_authors']  #类显示的字段,不写默认就是"__str__"
        list_display_links = ['price','publish','pub_date'] #指定可以跳到编辑页面的字段,就是说字段是不是超链接形式的
        list_filter = ['title','price']      #通过哪个字段筛选出我们要的信息
        search_fields = ['title'] #指定搜索的字段
        list_editable = ['title']  #指定的字段变成编辑框,可以在当前页面直接修改,不用跳转到编辑页面
        ordering = ['-price']       #默认升序
    class PublishConfig(admin.ModelAdmin):
        list_display = ['name','email','city']
    
    
    admin.site.register(Book,BookConfig)
    admin.site.register(AuthorDetail)
    admin.site.register(Author)
    admin.site.register(Publish,PublishConfig)

      效果图:

     admin源码分析

      单例模式

    单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。

    比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象。

    在 Python 中,我们可以用多种方法来实现单例模式:

    • 使用模块
    • 使用 __new__
    • 使用装饰器(decorator)
    • 使用元类(metaclass)

      使用 __new__

    class Singleton(object):
        _instance = None                                     #一开始_instance为None
        def __new__(cls, *args, **kw):             #每次应用类创建一个对象的时候,都会初始化构__new__函数来初始化对象
            if not cls._instance:                           #当你在执行初始化页面时候,如果没有_instance就创建对象
                cls._instance = super(Singleton, cls).__new__(cls, *args, **kw)   
            return cls._instance                                #如果已经存在了_instance就直接返回给你,所以,无论怎么样这个类都只会有唯一的一个对象

      执行情况如下:

    >>> one = MyClass()
    >>> two = MyClass()
    >>> one == two
    True
    >>> one is two
    True
    >>> id(one), id(two)
    (4303862608, 4303862608)

      使用模块

      其实,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()

     admin源码解析执行流程

    1.循环加载执行所有已经注册的app中的admin.py文件

    def autodiscover():
        autodiscover_modules('admin', register_to=site)  #去查看所有已经注册注册的app中的admin.py文件

      2. 注册模型类

    #admin.site: AdminSite的单例对象
    #admin.site.register(Book,BookConfig)
    #admin.site.register(Author)
    class ModelAdmin():
          pass
    
    
    class AdminSite():
         
         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)

      3. admin.site  

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

      <4> 执行register方法

    admin.site.register(Book, BookAdmin) 
    admin.site.register(Publish)
    class ModelAdmin(BaseModelAdmin):pass
    
    def register(self, model_or_iterable, admin_class=None, **options):
        if not admin_class:
                admin_class = ModelAdmin
        # Instantiate the admin class to save in the registry
        self._registry[model] = admin_class(model, self)

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

    print(admin.site._registry)   # 执行结果------------>结果一样,同一个字典

      到这里,注册结束!

      <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()方法的拓展(二级分发的应用)

    urlpatterns = [
        path('admin/', admin.site.urls),
        一级分发
        path('index/',([
            path('test01/',test01),
            path('test02/',test02)
                       ],None,None))
    
    
        二级分发,把原来放视图函数的地方用([],None,None)站位,然后在[]里面再写path('xx',xx)
            path('index/', ([
                                path('name/', ([
                                    path('sb',test01),
                                    path('dsb',test02)
                                                 ],None,None)),
                                path('sj/',([
                                    path('xiaomi',xiaomi),
                                    path('huawei',huawei),
                                    path('meizu',meizu)
                                            ],None,None))
                            ], None, None))
    ]



    #视图函数
    def test01(request):
    return HttpResponse('tset01....')

    def test02(request):
    return HttpResponse('tset02....')
    def xiaomi(request):
    return HttpResponse("小米")

    def huawei(request):
    return HttpResponse("华为")
    def meizu(request):
    return HttpResponse("魅族")
     

      <7>url()方法的拓展优化

    def get_urls():
    tem = []
    for model, config_obj in admin.site._registry.items():
    app_label = model._meta.app_label
    model_name = model._meta.model_name
    tem.append(
    path('%s/%s/'%(app_label,model_name),(get_urls2(),None,None))
    )
    return tem

    def get_urls2():
    tem = [
    path('',list_view),
    path('add/',add_view),
    re_path('(d+)/del/',del_view),
    re_path('(d+)/change/',change_view)
    ]
    return tem
     
    urlpatterns = [

        path('admin/', admin.site.urls),

        path('tom/', (get_urls(), None, None)),
    
    
        ]




    #视图函数
    def list_view(request):

    return HttpResponse('查看')


    def add_view(request):
    return HttpResponse("增加")


    def del_view(request,pk): #注意这边的编辑和删除接收到参数是多一个的
    return HttpResponse('删除视图')


    def change_view(request,pk):
    return HttpResponse('编辑视图')
     

      补充一个知识点:如何拿到模型类对应的类名小写和应用名称

    1.类名小写

      类名._meta.model_name

    2.应用名

      类名._meta.app_label
  • 相关阅读:
    pandas isin 和not in
    游戏开发需要学什么?
    打开页面,数字会自增的效果怎么弄?
    jq 导航栏点击添加/删除类(a标签跳转页面)
    bootstrap+jq分页
    2020/12/18
    2020/12/17
    2020/12/16
    2020/12/15
    2020/12/14
  • 原文地址:https://www.cnblogs.com/tjp40922/p/10267962.html
Copyright © 2020-2023  润新知