Django——admin管理工具

1、admin組件使用

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

  Django 自動管理工具是 django.contrib 的一部分。你能夠在項目的 settings.py 中的 INSTALLED_APPS 看到它:git

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    "app01"
]

  django.contrib是一套龐大的功能集,它是Django基本代碼的組成部分。 web

一、激活管理工具

  一般咱們在生成項目時會在 urls.py 中自動設置好,django

from django.conf.urls import url
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
]


from django.contrib import admin
from django.urls import path

urlpatterns = [
    path('admin/', admin.site.urls),
]

  當這一切都配置好後,Django 管理工具就能夠運行了。設計模式

二、使用管理工具

  啓動開發服務器,而後在瀏覽器中訪問 http://127.0.0.1:8000/admin/,獲得登錄界面,你能夠經過命令 python manage.py createsuperuser 來建立超級用戶。瀏覽器

  爲了讓 admin 界面管理某個數據模型,咱們須要先註冊該數據模型到 admin服務器

from django.db import models

# Create your models here.




class Author(models.Model):

    name=models.CharField( max_length=32)
    age=models.IntegerField()


    def __str__(self):
        return self.name

class Publish(models.Model):

    name=models.CharField( max_length=32)
    email=models.EmailField()

    def __str__(self):
        return self.name


class Book(models.Model):

    title = models.CharField( max_length=32)
    publishDate=models.DateField()
    price=models.DecimalField(max_digits=5,decimal_places=2)

    publisher=models.ForeignKey(to="Publish")
    authors=models.ManyToManyField(to='Author')

    def __str__(self):
        return self.title
models.py示例

三、admin的定製

  在admin.py中只須要講Model中的某個類註冊,便可在Admin中實現增刪改查的功能,如:session

from django.contrib import admin
from app01.models import *

admin.site.register(UserInfo)
admin.site.register(Book)
admin.site.register(Room)

  可是,這種方式比較簡單,若是想要進行更多的定製操做,須要利用ModelAdmin進行操做,如:app

方式一:
    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',)

ModelAdmin中提供了大量的可定製功能,如ide

 1. list_display,列表時,定製顯示的列。

# 模板
@admin.register(models.UserInfo)
class UserAdmin(admin.ModelAdmin):
    list_display = ('user', 'pwd', 'xxxxx')
 
    def xxxxx(self, obj):
        return "xxxxx"

  在MRBS系統上定製admin示例:

class BookConfig(admin.ModelAdmin):
    list_display = ["user", "room", "date"]   # 不能放多對多字段

admin.site.register(Book, BookConfig)   # 定製類繼承了ModelAdmin, 但優先顯示BookConfig類的,找不到再找父類的

  顯示效果:

  

2. list_display_links,列表時,定製列能夠點擊跳轉。

class BookConfig(admin.ModelAdmin):
    list_display = ["user", "room", "date"]   # 不能放多對多字段
    list_display_links = ["room", "date"]   # 自由定製哪一列能夠作跳轉

admin.site.register(Book, BookConfig)

  顯示效果:

  

3. list_filter,列表時,定製右側快速篩選。

class BookConfig(admin.ModelAdmin):
    list_display = ["user", "room", "date"]   # 不能放多對多字段
    list_display_links = ["room", "date"]   # 自由定製哪一列能夠作跳轉
    list_filter = ["user", "date"]   # 定製右側快速篩選

admin.site.register(Book, BookConfig)

  顯示效果:

  

4. list_select_related,列表時,連表查詢是否自動select_related

 

5. list_editable,列表時,能夠編輯的列

class BookConfig(admin.ModelAdmin):
    list_display = ["user", "room", "date"]   # 不能放多對多字段
    list_display_links = ["room", "date"]   # 自由定製哪一列能夠作跳轉
    list_filter = ["user", "date"]   # 定製右側快速篩選
    list_editable = ["user"]

admin.site.register(Book, BookConfig)

  須要注意的是設置爲list_editable就不能設置爲list_display_links。

  顯示效果

  

6. search_fields,列表時,模糊搜索的功能

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

  顯示效果:

  

7. date_hierarchy,列表時,對Date和DateTime類型進行搜索

class BookConfig(admin.ModelAdmin):
    list_display = ["user", "room", "date"]   # 不能放多對多字段
    list_display_links = ["room", "date"]   # 自由定製哪一列能夠作跳轉
    list_filter = ["user", "date"]   # 定製右側快速篩選
    list_editable = ["user"]
    search_fields = ['date']

    date_hierarchy = 'date'

admin.site.register(Book, BookConfig)

  顯示效果:

  

8. inlines,詳細頁面,若是有其餘表和當前表作FK,那麼詳細頁面能夠進行動態增長和刪除(不經常使用)

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

9. action,列表時,定製action中的操做

  自帶的action操做是一個批量選中刪除的操做:

  

  點擊go即完成刪除操做。

自定製action的操做:

class BookConfig(admin.ModelAdmin):
    ...
    # 定製Action行爲具體方法
    def func(self, request, queryset):
        print(self, request, queryset)
        queryset.update(date="2012-12-12")

    func.short_description = "批量初始化操做"
    actions = [func, ]

    # Action選項都是在頁面上方顯示
    actions_on_top = True
    # Action選項都是在頁面下方顯示
    actions_on_bottom = False

    # 是否顯示選擇個數
    actions_selection_counter = True

admin.site.register(Book, BookConfig)

  點選並選擇批量初始化後,顯示效果以下:

  

10. 定製HTML模板

add_form_template = None
change_form_template = None
change_list_template = None
delete_confirmation_template = None
delete_selected_confirmation_template = None
object_history_template = None

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

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

12.  fields,詳細頁面時,顯示字段的字段 

添加頁面原始顯示:
      

  修改了添加頁面的顯示字段:

class BookConfig(admin.ModelAdmin):
    ...
    fields = ['user', ]

   修改後顯示效果:

  

13. exclude,詳細頁面時,排除的字段

class BookConfig(admin.ModelAdmin):
    ...
    # fields = ['user', ]
    exclude = ['user', 'room']

  與fields相反,排除哪些字段不顯示,顯示效果以下:

  

14.  readonly_fields,詳細頁面時,只讀字段

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

15. 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'),
        }),
    )

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

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

17. ordering,列表時,數據排序規則

class BookConfig(admin.ModelAdmin):
    list_display = ["id", "user", "room", "date"]   # 不能放多對多字段
    ordering = ["id"]

  添加「id」字段顯示,並進行排序,顯示以下:

  

  在添加的字段前加「-」,便是反向排序:

class BookConfig(admin.ModelAdmin):
    ordering = ['-date']   # 反向排序

  ordering = []中能夠添加多個字段,但不是聯合排序,而是在第一個字段排序相同的狀況下,按第二個字段排序。

class BookConfig(admin.ModelAdmin):
    ordering = ['-date', "time_id"]  

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

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

19. 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 = "指定列數據爲空時,默認顯示"

2、單例模式

  單例模式(Singleton Pattern)是一種經常使用的軟件設計模式,該模式的主要目的是確保某一個類只有一個實例存在。當你但願在整個系統中,某個類只能出現一個實例時,單例對象就能派上用場。

  好比,某個服務器程序的配置信息存放在一個文件中,客戶端經過一個 AppConfig 的類來讀取配置文件的信息。若是在程序運行期間,有不少地方都須要使用配置文件的內容,也就是說,不少地方都須要建立 AppConfig 對象的實例,這就致使系統中存在多個 AppConfig 的實例對象,而這樣會嚴重浪費內存資源,尤爲是在配置文件內容不少的狀況下。事實上,相似 AppConfig 這樣的類,咱們但願在程序運行期間只存在一個實例對象。

  在 Python 中,咱們能夠用多種方法來實現單例模式:

  • 使用模塊
  • 使用 __new__
  • 使用裝飾器(decorator)
  • 使用元類(metaclass)

一、使用__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


one = MyClass()
one.a = 3

two = MyClass()
print(two.a)
print("one", id(one))
print("tow", id(two))
"""
3
one 4362186704
tow 4362186704
"""

  在上面的代碼中,咱們將類的實例和一個類變量 _instance 關聯起來,若是 cls._instance 爲 None 則建立實例,不然直接返回 cls._instance

  經過執行狀況能夠看到,建立的兩個實例內存地址相同,實際上是一個對象。所以第一個對象修改a的值後,建立第二對象其實只是指向這個內存地址,a的值也是被修改過的。

二、使用模塊

  其實,Python 的模塊就是自然的單例模式,由於模塊在第一次導入時,會生成 .pyc 文件,當第二次導入時,就會直接加載 .pyc 文件,而不會再次執行模塊代碼。所以,咱們只需把相關的函數和數據定義在一個模塊中,就能夠得到一個單例對象了。

(1)示例驗證:

  mysingleton.py:

class My_Singleton(object):
    x = 12

    def foo(self):
        print(self.x)


my_singleton = My_Singleton()
print("OK")

  main.py:

from mysingleton import my_singleton

print(id(my_singleton))


from mysingleton import my_singleton

print(id(my_singleton))


"""
OK
4366742976
4366742976
"""

  注意這裏的導入的不是類仍是實例對象。

  這裏只打印了一次「OK」,這是由於第一次導入模塊的時,就已經將代碼執行了一遍。加載過程當中生成了一個.pyc中間文件。將執行中拿到變量放到.pyc文件中。再一次導入模塊時,再也不執行代碼,而是直接去.pyc文件中存好的實例對象中拿取變量。

(2)示例驗證2

mysingleton.py:

class My_Singleton(object):
    x = 12

    def foo(self):
        print(self.x)


my_singleton = My_Singleton()

print("OK")

func.py:

from mysingleton import my_singleton

def foo():
    print(id(my_singleton))

main.py:

from mysingleton import my_singleton

print(id(my_singleton))


from mysingleton import my_singleton

print(id(my_singleton))


from func import *

foo()

"""
OK
4362186536
4362186536
4362186536
"""

  一個程序無論導入的形式如何變換,仍是從同一個.pyc文件中去取。

  程序跑起來後,導入一次後,只要仍是程序過程當中,其餘地方的導入拿到的實例對象和以前那個實例對象是一個對象。

3、admin源碼執行流程

一、循環加載執行全部已經註冊的app中的admin.py文件

def autodiscover():
    autodiscover_modules('admin', register_to=site)

二、執行代碼

#admin.py

class BookAdmin(admin.ModelAdmin):
    list_display = ("title",'publishDate', 'price')

admin.site.register(Book, BookAdmin) 

admin.site.register(Publish)

三、admin.site  

  這裏應用的是一個單例模式,對於AdminSite類的一個單例模式,執行的每個app中的每個admin.site都是一個對象

四、執行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)   # 執行結果?

  在一個程序裏,只要用到admin.site無論在幾個app中都是一個對象。所以admin.site._registry執行結果都是獲得全部的註冊對象。

  到這裏,註冊結束!

五、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

六、url()方法的擴展應用

from django.shortcuts import HttpResponse
def test01(request):
    return HttpResponse("test01")

def test02(request):
    return HttpResponse("test02")

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^yuan/', ([
                    url(r'^test01/', test01),
                    url(r'^test02/', test02),

                    ],None,None)),
]

  運用url()方法分發的示例:

urlpatterns = [
    path('admin/', admin.site.urls),
    ...
    url(r"^yuan/", ([
        url(r'^test01/', ([
            url(r'^test04/', test04),
            url(r'^test05/', test05),
        ], None, None)),
        url(r'^test02/', test02),
        url(r'^test03/', test03),
    ], None, None))
]

   擴展優化

from django.conf.urls import url,include
from django.contrib import admin

from django.shortcuts import HttpResponse

def change_list_view(request):
    return HttpResponse("change_list_view")
def add_view(request):
    return HttpResponse("add_view")
def delete_view(request):
    return HttpResponse("delete_view")
def change_view(request):
    return HttpResponse("change_view")

def get_urls():

    temp=[
        url(r"^$".format(app_name,model_name),change_list_view),
        url(r"^add/$".format(app_name,model_name),add_view),
        url(r"^\d+/del/$".format(app_name,model_name),delete_view),
        url(r"^\d+/change/$".format(app_name,model_name),change_view),
    ]

    return temp


url_list=[]

for model_class,obj in admin.site._registry.items():

    model_name=model_class._meta.model_name
    app_name=model_class._meta.app_label

    # temp=url(r"{0}/{1}/".format(app_name,model_name),(get_urls(),None,None))
    temp=url(r"{0}/{1}/".format(app_name,model_name),include(get_urls()))
    url_list.append(temp)

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^yuan/', (url_list,None,None)),
]

七、仿admin的url轉發

"""MRBS URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/2.0/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from app01 import views
from django.conf.urls import url

from django.shortcuts import HttpResponse


def yuan(request):
    return HttpResponse("Yuan")


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")


def add(request):
    return HttpResponse("add")


def delete(request, id):
    return HttpResponse("delete")


def change(request, id):
    return HttpResponse("change")


def list_view(request):
    return HttpResponse("list_view")

def get_urls2():

    temp = []
    temp.append(url(r"^add/",add))
    temp.append(url(r"^(\d+)/delete/",delete))
    temp.append(url(r"^(\d+)/change/",change))
    temp.append(url(r"^$",list_view))
    return temp


def get_urls():
    temp = []
    print('_registry:', admin.site._registry)  # 鍵值就是全部的註冊表

    for model, admin_class in admin.site._registry.items():
        print("model", model)
        print("admin_class", admin_class)  # app01.BookConfig
        """
        全部的註冊模型表
        model <class 'django.contrib.auth.models.Group'>
        model <class 'app01.models.Book'>
        model <class 'app01.models.UserInfo'>
        model <class 'app01.models.Room'>
        """
        # temp.append(path(r"app01/book", yuan))
        # temp.append(path(r"%s/%s" % (app名稱怎麼取?, 模型名稱怎麼取?), yuan))
        # 如何經過model類變量獲取該模型的字符串名稱和該模型所在的app的字符串名稱?
        # print("====>>", model._meta.model_name)   # 模型名稱  book/userinfo/room
        # print("====>>", model._meta.app_label)    # app名稱  app01

        model_name = model._meta.model_name
        app_label = model._meta.app_label
        temp.append(path(r"%s/%s/" % (app_label, model_name), (get_urls2(), None, None)))

    return temp

urlpatterns = [
    path('admin/', admin.site.urls),
    path('login/', views.login),
    path('index/', views.index),
    path('book/', views.book),

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

 注意:

(1)admin.site單例對象,admin.site._registry拿到全部的註冊對象,形式以下所示:

_registry: 
{<class 'django.contrib.auth.models.Group'>: <django.contrib.auth.admin.GroupAdmin object at 0x105d24f98>,
<class 'app01.models.Book'>: <app01.admin.BookConfig object at 0x105d6d470>,
<class 'app01.models.UserInfo'>: <django.contrib.admin.options.ModelAdmin object at 0x105d6d5c0>,
<class 'app01.models.Room'>: <django.contrib.admin.options.ModelAdmin object at 0x105d6d5f8>}

(2)循環遍歷admin.site._registry, 拿到全部的註冊模型表

def get_urls():
    temp = []
    print('_registry:', admin.site._registry)  # 鍵值就是全部的註冊表

    for model, admin_class in admin.site._registry.items():
        print("model", model)
        # print("admin_class", admin_class)  # app01.BookConfig
        """
        全部的註冊模型表
        model <class 'django.contrib.auth.models.Group'>
        model <class 'app01.models.Book'>
        model <class 'app01.models.UserInfo'>
        model <class 'app01.models.Room'>
        """

(3)經過model類變量獲取該模型的字符串名稱和該模型所在的app的字符串名稱。

def get_urls():
    temp = []

    for model, admin_class in admin.site._registry.items():

        # temp.append(path(r"app01/book", yuan))
        # temp.append(path(r"%s/%s/" % (app名稱怎麼取?, 模型名稱怎麼取?), yuan))
        # 如何經過model類變量獲取該模型的字符串名稱和該模型所在的app的字符串名稱?
        print("====>>", model._meta.model_name)   # 模型名稱  book/userinfo/room
        print("====>>", model._meta.app_label)    # app名稱  app01

(4)根據拿到的模型名和app名稱,拼接路徑並添加到列表中。

  根據url多級分發規則:url(r"^yuan/"([url(r'^app01/book/',([url(r'12/delete/')],None,None)), ],None,None))

def get_urls2():
    temp = []
    temp.append(url(r"^add/",add))
    temp.append(url(r"^(\d+)/delete/",delete))
    temp.append(url(r"^(\d+)/change/",change))
    temp.append(url(r"^$",list_view))
    return temp

def get_urls():
    temp = []
    for model, admin_class in admin.site._registry.items():
        model_name = model._meta.model_name
        app_label = model._meta.app_label
        temp.append(path(r"%s/%s/" % (app_label, model_name), (get_urls2(), None, None)))

    return temp


urlpatterns = [
    path('admin/', admin.site.urls),
    path('yuan/', (get_urls(), None, None)),
]

  顯示效果:

  

相關文章
相關標籤/搜索