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

猜你喜欢

转载自www.cnblogs.com/yipianshuying/p/10278471.html
062