Django-admin用法和源碼分析

1、單例模式:單個實例公用一個對象html

一、基於模塊的單例模式python

s1.py文件:git

class Foo(object):
    def test(self):
        print("123")
v = Foo()


s2.py文件:web

from s1 import v as v1
print(v1,id(v1))  #<s1.Foo object at 0x0000000002221710> 35788560
from s1 import v as v2
print(v1,id(v2))   #<s1.Foo object at 0x0000000002221710> 35788560
# 兩個的內存地址是同樣的
# 文件加載的時候,第一次導入後,再次導入時不會再從新加載。


二、基於new方法的單例模式數據庫

class Singleton:
    def __new__(cls, *args, **kw):
        '''__new__是一個構造方法,self就是他構造的'''
        if not hasattr(cls, '_instance'):
            orig = super(Singleton, cls)
            cls._instance = orig.__new__(cls, *args, **kw)
        return cls._instance
one = Singleton()
two = Singleton()
print(one,two)   #他們兩個的地址同樣
# print(id(one),id(two))
one.name = 'alex'
print(two.name)


2、Django-admin使用流程django

一、數據庫遷移session

models.py文件:app

from django.db import models
class Author(models.Model):
    nid = models.AutoField(primary_key=True)
    name=models.CharField( max_length=32)
    age=models.IntegerField()
    def __str__(self):
        return self.name
class Publish(models.Model):
    nid = models.AutoField(primary_key=True)
    name=models.CharField( max_length=32)
    city=models.CharField( max_length=32)
    email=models.EmailField()
    def __str__(self):
        return self.name
class Book(models.Model):
    nid = models.AutoField(primary_key=True,verbose_name="編號")
    title = models.CharField( max_length=32,verbose_name="名稱")
    publishDate=models.DateField()
    price=models.DecimalField(max_digits=5,decimal_places=2,verbose_name="價格")
    # 與Publish創建一對多的關係,外鍵字段創建在多的一方
    publish=models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE)
    # 與Author表創建多對多的關係,ManyToManyField能夠建在兩個模型中的任意一個,自動建立第三張表
    authors=models.ManyToManyField(to='Author',)
    def __str__(self):
        return self.title
        
#執行下面python語句生成相關表(數據遷移)
# python3 manage.py makemigrations
# python3 manage.py migrate


二、建立超級用戶ide

# python3 manage.py createsuperuser


三、admin.py中註冊表函數

from django.contrib import admin
from app01 import models

admin.site.register(models.Book)
admin.site.register(models.Publish)
admin.site.register(models.Author)


四、若是新建應用app02

# python3 manage.py startapp app02


settings.py文件添加內容:

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應用的models.py增長表,接着數據庫遷移,在app02應用的admin.py中對錶進行註冊


3、admin源碼分析

一、訪問url

def get_urls():
    temp = [
        url(r'^$'.format(app_name, cls_name), change_list),
        url(r'^add/$'.format(app_name, cls_name), add_view),
        url(r'^del/$'.format(app_name, cls_name), delete_view),
        url(r'^change/$'.format(app_name, cls_name), change_view)
    ]
    return temp
url_list = []
for model_class, v in admin.site._registry.items():
    cls_name = model_class._meta.model_name  # 當前類名稱的小寫
    app_name = model_class._meta.app_label  # 當前app的名稱
    方式一:
    # all_urls = url(r'^{0}/{1}/'.format(app_name,cls_name), (get_urls(),None,None,))
    方式二:
    all_urls = url(r'^{0}/{1}/'.format(app_name, cls_name), include(get_urls()))
    url_list.append(all_urls)
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    # admin.site這個對象裏面有一個屬性_registry = {}
    # 點擊urls查看源碼返回的是一個元組,元組的第一個元素是一個列表
    url(r'^index/', (
        [
            url(r'^app01/userinfo/', ([
                                          url(r'^$', change_list, name="login"),
                                          url(r'^add/$', add_view, name="login"),
                                          url(r'^(\d+)/del/$', delete_view, name="login"),
                                          url(r'^(\d+)/change/$', change_view, name="login"),
                                      ], None, None), name="login"),
            url(r'^app01/usertype/', ([
                                          url(r'^$', change_list, name="login"),
                                          url(r'^add/$', add_view, name="login"),
                                          url(r'^(\d+)/del/$', delete_view, name="login"),
                                          url(r'^(\d+)/change/$', change_view, name="login"),
                                      ], None, None), name="login"), ], None, None)),
    url(r'^app02/article/', ([
                                 url(r'^$', change_list, name="login"),
                                 url(r'^add/$', add_view, name="login"),
                                 url(r'^(\d+)/del/$', delete_view, name="login"),
                                 url(r'^(\d+)/change/$', change_view, name="login"),
                             ], None, None), name="login"),
    # index和index2的兩個是同樣的,咱們能夠用index2的方式替代index
    url(r'^index2/', (url_list, None, None,)),
]


二、admin源碼流程

a. 運行程序,找到每個app中的 admin.py 文件,並加載
    - app01.admin.py
        - 建立admin.site中的對象
        - 執行對象的 register方法,目的:將註冊類添加到 _registry中
            _registry = {
                key是傳進來的model   value:是ModelAdmin的對象,傳了兩個參數
                models.Role: ModelAdmin(models.Role,admin.site),
                models.UserInfo: ModelAdmin(models.UserInfo,admin.site)
                models.UserType: ModelAdmin(models.UserType,admin.site)
            }
    - app02.admin.py
        - 用app01.admin中建立那個admin.site對象
        - 執行對象的 register方法,目的:講註冊類添加到 _registry中
            _registry = {
                models.Role: ModelAdmin(models.Role,admin.site),
                models.UserInfo: ModelAdmin(models.UserInfo,admin.site)
                models.UserType: ModelAdmin(models.UserType,admin.site)
                models.Article: ModelAdmin(models.Article,admin.site)
            }
    admin.site是一個對象(單例模式建立),其中封裝了:
        _registry = {
            models.Role: ModelAdmin(models.Role,admin.site),
            models.UserInfo: ModelAdmin(models.UserInfo,admin.site)
            models.UserType: ModelAdmin(models.UserType,admin.site)
            models.Article: ModelAdmin(models.Article,admin.site)
        }
b. urls.py
    再次調用 admin.site 對象的 urls屬性:
        urlpatterns = [
            url(r'^admin/', admin.site.urls),
        ]
    class ModelAdmin(object):
        def __init__(self,model_class,site):
            self.model_class = model_class
            self.site = site
        def changelist_view(self,request):
            data_list = self.model_class.objects.all()   #是動態的
            return HttpResponse('列表頁面')
        def add_view(self,request):
            return HttpResponse('添加頁面')
        def delete_view(self,request,nid):
            return HttpResponse('刪除頁面')
        def change_view(self,request,nid):
            return HttpResponse('修改頁面')
        def get_urls(self):
             urlpatterns = [
                url(r'^$', self.changelist_view),
                url(r'^add/$', self.add_view),
                url(r'^(.+)/delete/$', self.delete_view),
                url(r'^(.+)/change/$', self.change_view),
            ]
            return urlpatterns
        @property
        def urls(self):
            return self.get_urls()
    class AdminSite(object):
        def __init__(self):
            self._registry = {}
        def register(self,model_class,model_admin):
            self._registry[model_class] = model_admin(model_class,self)
        def get_urls(self):
            """
            models.Role: ModelAdmin(models.Role,admin.site),
            models.UserInfo: ModelAdmin(models.UserInfo,admin.site)
            models.UserType: ModelAdmin(models.UserType,admin.site)
            models.Article: ModelAdmin(models.Article,admin.site)
            """
            url_list = []
            for model_class,model_admin in self._registry.items():
                model_class是一個類
                app_name = model_class._meta.app_label
                model_name = model_class._meta.model_name
                url_list += [
                    url('%s/%s' %(app_name,model_name,), include(model_admin.urls))
                ]
            return url_list
        @property
        def urls(self):
            return (self.get_urls(), None,None )


4、Django-admin(web頁面顯示)


models.py文件:

from django.db import models
class Author(models.Model):
    nid = models.AutoField(primary_key=True)
    name=models.CharField( max_length=32)
    age=models.IntegerField()
    # 與AuthorDetail創建一對一的關係
    authorDetail=models.OneToOneField(to="AuthorDetail",on_delete=models.CASCADE)
    def __str__(self):
        return self.name
class AuthorDetail(models.Model):
    nid = models.AutoField(primary_key=True)
    birthday=models.DateField()
    telephone=models.BigIntegerField()
    addr=models.CharField( max_length=64)
class Publish(models.Model):
    nid = models.AutoField(primary_key=True)
    name=models.CharField( max_length=32)
    city=models.CharField( max_length=32)
    email=models.EmailField()
    def __str__(self):
        return self.name
class Book(models.Model):
    nid = models.AutoField(primary_key=True)
    title = models.CharField( max_length=32)
    publishDate=models.DateField()
    price=models.DecimalField(max_digits=5,decimal_places=2)
    # 與Publish創建一對多的關係,外鍵字段創建在多的一方
    publish=models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE)
    # 與Author表創建多對多的關係,ManyToManyField能夠建在兩個模型中的任意一個,自動建立第三張表
    authors=models.ManyToManyField(to='Author',)


admin.py文件:

from django.contrib import admin
# Register your models here.
from .models import *
#定製功能
class BookConfig(admin.ModelAdmin):
    list_display = ["nid","title","price","publishDate","publish"]      #顯示的列
    list_display_links=["title","price"]                                             #字段能夠點擊跳轉
    list_filter=["title","publish"]                                                     #定製右側快速篩選
    search_fields=["title"]                                                             #列表時,模糊搜索的功能
    
    def patch_init(self,request,queryset):                                    #批量操做執行的函數
        queryset.update(price=100)
    patch_init.short_description = "批量初始化"                        #批量操做顯示的描述
    actions = [patch_init] 
                                                             #對所選擇的選項執行批量操做函數
    #change_list_template="list.html"                                    #定製HTML模板
    ordering=("price","nid",)                                                  #數據排序規則
    
    
admin.site.register(Book,BookConfig)      #第一個參數是對哪一個表進行註冊,第二個參數是新增的自定義的功能類,這樣book頁面就會顯示新的功能了
admin.site.register(Publish)
admin.site.register(Author)
admin.site.register(AuthorDetail)


其餘的一些定製功能:

一、分頁

# 分頁,每頁顯示條數
    list_per_page = 100
# 分頁,顯示所有(真實數據<該值時,纔會有顯示所有)
    list_max_show_all = 200
# 分頁插件
    paginator = Paginator

二、list_editable,列表時,能夠編輯的列

@admin.register(models.UserInfo)
class UserAdmin(admin.ModelAdmin):
    list_display = ('user', 'pwd','ug',)
    list_editable = ('ug',)

三、date_hierarchy,列表時,對Date和DateTime類型進行搜索

@admin.register(models.UserInfo)
class UserAdmin(admin.ModelAdmin):
    date_hierarchy = 'ctime'

四、preserve_filters,詳細頁面,刪除、修改,更新後跳轉回列表後,是否保留原搜索條件

五、save_as = False,詳細頁面,按鈕爲「Sava as new」 或 「Sava and add another」

save_as_continue = True
# 若是 save_as=True,save_as_continue = True, 點擊Sava as new 按鈕後繼續編輯。
# 若是 save_as=True,save_as_continue = False,點擊Sava as new 按鈕後返回列表。

六、save_on_top = False,詳細頁面,在頁面上方是否也顯示保存刪除等按鈕

七、inlines,詳細頁面,若是有其餘表和當前表作FK,那麼詳細頁面能夠進行動態增長和刪除

class UserInfoInline(admin.StackedInline): # TabularInline
    extra = 0
    model = models.UserInfo
    
class GroupAdminMode(admin.ModelAdmin):
    list_display = ('id', 'title',)
    inlines = [UserInfoInline, ]

八、raw_id_fields,詳細頁面,針對FK和M2M字段變成以Input框形式

@admin.register(models.UserInfo)
class UserAdmin(admin.ModelAdmin):
    raw_id_fields = ('FK字段', 'M2M字段',)

九、fields,詳細頁面時,顯示字段的字段

@admin.register(models.UserInfo)
class UserAdmin(admin.ModelAdmin):
    fields = ('user',)

十、exclude,詳細頁面時,排除的字段

@admin.register(models.UserInfo)
class UserAdmin(admin.ModelAdmin):
    exclude = ('user',)

十一、readonly_fields,詳細頁面時,只讀字段

@admin.register(models.UserInfo)
class UserAdmin(admin.ModelAdmin):
    readonly_fields = ('user',)

十二、fieldsets,詳細頁面時,使用fieldsets標籤對數據進行分割顯示

@admin.register(models.UserInfo)
class UserAdmin(admin.ModelAdmin):
    fieldsets = (
        ('基本數據', {
            'fields': ('user', 'pwd', 'ctime',)
        }),
        ('其餘', {
            'classes': ('collapse', 'wide', 'extrapretty'),  # 'collapse','wide', 'extrapretty'
            'fields': ('user', 'pwd'),
        }),
    )


1三、詳細頁面時,M2M顯示時,數據移動選擇(方向:上下和左右)

@admin.register(models.UserInfo)
class UserAdmin(admin.ModelAdmin):
    filter_vertical = ("m2m字段",) # 或filter_horizontal = ("m2m字段",)

1四、view_on_site,編輯時,是否在頁面上顯示view on set

view_on_site = False
或
def view_on_site(self, obj):
    return 'https://www.baidu.com'

1五、radio_fields,詳細頁面時,使用radio顯示選項(FK默認使用select)

radio_fields = {"ug": admin.VERTICAL} # 或admin.HORIZONTAL

1六、show_full_result_count = True,列表時,模糊搜索後面顯示的數據個數樣式

@admin.register(models.UserInfo)
class UserAdmin(admin.ModelAdmin):
    # show_full_result_count = True # 1 result (12 total)
    # show_full_result_count = False  # 1 result (Show all)
    search_fields = ('user',)

1七、formfield_overrides = {},詳細頁面時,指定現實插件

from django.forms import widgets
from django.utils.html import format_html
class MyTextarea(widgets.Widget):
    def __init__(self, attrs=None):
        # Use slightly better defaults than HTML's 20x2 box
        default_attrs = {'cols': '40', 'rows': '10'}
        if attrs:
            default_attrs.update(attrs)
        super(MyTextarea, self).__init__(default_attrs)
    def render(self, name, value, attrs=None):
        if value is None:
            value = ''
        final_attrs = self.build_attrs(attrs, name=name)
        return format_html('<textarea {}>\r\n{}</textarea>',final_attrs, value)
        
@admin.register(models.UserInfo)
class UserAdmin(admin.ModelAdmin):
    formfield_overrides = {
        models.models.CharField: {'widget': MyTextarea},
    }

1八、prepopulated_fields = {},添加頁面,當在某字段填入值後,自動會將值填充到指定字段。

@admin.register(models.UserInfo)
class UserAdmin(admin.ModelAdmin):
    prepopulated_fields = {"email": ("user","pwd",)}
    
PS: DjangoAdmin中使用js實現功能,頁面email字段的值會在輸入:user、pwd時自動填充

1九、form = ModelForm,用於定製用戶請求時候表單驗證

from app01 import models
from django.forms import ModelForm
from django.forms import fields
class MyForm(ModelForm):
    others = fields.CharField()
    class Meta:
        model = models = models.UserInfo
        fields = "__all__"
        
@admin.register(models.UserInfo)
class UserAdmin(admin.ModelAdmin):
    form = MyForm

20、empty_value_display = "列數據爲空時,顯示默認值"

@admin.register(models.UserInfo)
class UserAdmin(admin.ModelAdmin):
    empty_value_display = "列數據爲空時,默認顯示"
    list_display = ('user','pwd','up')
    def up(self,obj):
        return obj.user
    up.empty_value_display = "指定列數據爲空時,默認顯示"
相關文章
相關標籤/搜索