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