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
原文地址:https://www.cnblogs.com/tjp40922/p/10267962.html