django-admin之ModelAdmin最全解釋


如果只是在admin中簡單的展示及管理模型,那么在admin.py模塊中使用admin.site.register將模型注冊一下就好了:

from django.contrib import admin from myproject.myapp.models import Author admin.site.register(Author) 

但是,很多時候這遠遠不夠,我們需要對admin進行各種深度定制,以滿足我們的需求。

這就要使用Django為我們提供的ModelAdmin類了。

ModelAdmin類是一個模型在admin頁面里的展示方法,如果你對默認的admin頁面滿意,那么你完全不需要定義這個類,直接使用最原始的樣子也行。通常,它們保存在app的admin.py文件里。下面是個簡單的例子:

from django.contrib import admin from myproject.myapp.models import Author # 創建一個ModelAdmin的子類 class AuthorAdmin(admin.ModelAdmin): pass # 注冊的時候,將原模型和ModelAdmin耦合起來 admin.site.register(Author, AuthorAdmin) 

一、注冊裝飾器

除了常用的admin.site.register(Author, AuthorAdmin)方式進行注冊,還可以用裝飾器的方式連接模型和ModelAdmin。如下所示:

from django.contrib import admin from .models import Author @admin.register(Author) class AuthorAdmin(admin.ModelAdmin): pass 

這個裝飾器可以接收一些模型類作為參數,以及一個可選的關鍵字參數site(如果你使用的不是默認的AdminSite),比如。

from django.contrib import admin from .models import Author, Reader, Editor from myproject.admin_site import custom_admin_site @admin.register(Author, Reader, Editor, site=custom_admin_site) class PersonAdmin(admin.ModelAdmin): pass 

二、 搜索admin文件

當你在INSTALLED_APPS設置中添加了django.contrib.admin后,Django將自動在每個應用中搜索admin模塊並導入它。也就是說,通常我們在每個app下都有一個admin.py文件,將當前app和admin有關的內容寫到內部的admin.py文件中就可以了,Django會自動搜索並應用它們。

  • class apps.AdminConfig:admin默認的AppConfig類,當Django啟動時自動調用其autodiscover()方法
  • class apps.SimpleAdminConfig:和上面的類似,但不調用autodiscover()
  • autodiscover()[source]:自動搜索admin模塊的方法。在使用自定義的site時,必須禁用這個方法,你應該在INSTALLED_APPS設置中用django.contrib.admin.apps.SimpleAdminConfig替代django.contrib.admin

三、ModelAdmin的屬性

真正用來定制admin的手段,大部分都集中在這些ModelAdmin內置的屬性上。

ModelAdmin非常靈活,它有許多內置屬性,幫助我們自定義admin的界面和功能。所有的屬性都定義在ModelAdmin的子類中,如下方式:

from django.contrib import admin class AuthorAdmin(admin.ModelAdmin): date_hierarchy = 'pub_date' 

1. ModelAdmin.actions

一個列表,包含自定義的actions,后面有專門的敘述。

2. ModelAdmin.actions_on_top

是否在列表上方顯示actions的下拉框,默認為True

3. ModelAdmin.actions_on_bottom

是否在列表下方顯示actions的下拉框,默認為False。效果看下面的圖片,沒什么大用途。

1.png-50.1kB

4. ModelAdmin.actions_selection_counter

是否在actions下拉框右側顯示選中的對象的數量,默認為True,可改為False。

2.png-6.6kB

5. ModelAdmin.date_hierarchy

根據你指定的日期相關的字段,為頁面創建一個時間導航欄,可通過日期過濾對象。例如:

date_hierarchy = 'pub_date'

它的效果看起來是這樣的:

3.png-38.4kB

6. ModelAdmin.empty_value_display

指定空白顯示的內容。如果你有些字段沒有值(例如None,空字符串等等),默認情況下會顯示破折號“-”。這個選項可以讓你自定義顯示什么,如下例就顯示為“-empty-”:

from django.contrib import admin class AuthorAdmin(admin.ModelAdmin): empty_value_display = '-empty-' 

你還可以為整個admin站點設置默認空白顯示值,通過設置AdminSite.empty_value_display="xxxxxxx"。甚至為某個函數設置空白值,如下:

from django.contrib import admin class AuthorAdmin(admin.ModelAdmin): fields = ('name', 'title', 'view_birth_date') def view_birth_date(self, obj): return obj.birth_date # 注意下面這句 view_birth_date.empty_value_display = '???' 

7. ModelAdmin.exclude

不顯示指定的某些字段。如下例有這么個模型:

from django.db import models class Author(models.Model): name = models.CharField(max_length=100) title = models.CharField(max_length=3) birth_date = models.DateField(blank=True, null=True) 

如果你不希望在頁面內顯示birth_date字段,那么這么設置:

from django.contrib import admin class AuthorAdmin(admin.ModelAdmin): fields = ('name', 'title') 

和這么設置是一樣的:

from django.contrib import admin class AuthorAdmin(admin.ModelAdmin): # 一定注意了,值是個元組!一個元素的時候,最后的逗號不能省略。 exclude = ('birth_date',) 

8. ModelAdmin.fields

按你希望的順序,顯示指定的字段。與exclude相對。但要注意與list_display區分。這里有個小技巧,你可以通過組合元組的方式,讓某些字段在同一行內顯示,例如下面的做法“url”和“title”將在一行內,而“content”則在下一行。

class FlatPageAdmin(admin.ModelAdmin): fields = (('url', 'title'), 'content') 

如果沒有對field或fieldsets選項進行定義,那么Django將按照模型定義中的順序,每一行顯示一個字段的方式,逐個顯示所有的非AutoField和editable=True的字段。(自動字段,如主鍵,不可編輯字段是不會出現在頁面里的。)

9. ModelAdmin.fieldsets

這個功能其實就是根據字段對頁面進行分組顯示或布局了。fieldsets是一個二元元組的列表。每個二元元組代表一個<fieldset>,是整個form的一部分。

二元元組的格式為(name,field_options),name是一個表示該filedset標題的字符串,field_options是一個包含在該filedset內的字段列表。

下面是一個例子,有助於你理解:

from django.contrib import admin class FlatPageAdmin(admin.ModelAdmin): fieldsets = ( (None, { 'fields': ('url', 'title', 'content', 'sites') }), ('Advanced options', { 'classes': ('collapse',), 'fields': ('registration_required', 'template_name'), }), ) 

它的頁面看起來像下面的樣子:

4.png-103.9kB

filed_options字典內,可以使用下面這些關鍵字:

fields:一個必填的元組,包含要在fieldset中顯示的字段。例如:

{
'fields': ('first_name', 'last_name', 'address', 'city', 'state'),
}

同樣,它也可以像前面那樣通過組合元組,實現多個字段在一行內的效果:

{
'fields': (('first_name', 'last_name'), 'address', 'city', 'state'),
}

fileds可以包含readonly_fields的值,作為只讀字段。

classes:一個包含額外的CSS類的元組,例如:

{
'classes': ('wide', 'extrapretty'),
}

兩個比較有用的樣式是collaspewide,前者將fieldsets折疊起來,后者讓它具備更寬的水平空間。

description:一個可選的額外的說明文本,放置在每個fieldset的頂部。但是,這里並沒有對description的HTML語法進行轉義,因此可能有時候會造成一些莫名其妙的顯示,要忽略HTML的影響,請使用django.utils.html.escape()手動轉義。

10. ModelAdmin.filter_horizontal

水平擴展多對多字段。默認情況下,ManyTOManyField在admin的頁面中會顯示為一個select框。在需要選擇大量對象時,這會有點困難。將ManyTOManyField添加到這個屬性列表里后,頁面就會對字段進行擴展,並提供過濾功能。如下圖:

5.png-55.9kB

11. ModelAdmin.filter_vertical

與上面的類似,不過是改成垂直布置了。

12. ModelAdmin.form

默認情況下,admin系統會為你的模型動態的創建ModelForm,它用於創建你的添加/修改頁面的表單。我們可以編寫自定義的ModelForm,在"添加/修改"頁面覆蓋默認的表單行為。

注意:如果你的ModelForm和ModelAdmin同時定義了exclude選項,那么ModelAdmin中的具有優先權,如下例所示,"age"字段將被排除,但是“name”字段將被顯示:

from django import forms from django.contrib import admin from myapp.models import Person class PersonForm(forms.ModelForm): class Meta: model = Person exclude = ['name'] class PersonAdmin(admin.ModelAdmin): exclude = ['age'] form = PersonForm 

13. ModelAdmin.formfield_overrides

這個屬性比較難以理解,通過一個列子來解釋可能會更好一點。設想一下我們自己寫了個RichTextEditorWidget(富文本控件),然后想用它來代替傳統的<textarea>(文本域控件)用於輸入大段文字。我們可以這么做:

from django.db import models from django.contrib import admin # 從對應的目錄導入我們先前寫好的widget和model from myapp.widgets import RichTextEditorWidget from myapp.models import MyModel class MyModelAdmin(admin.ModelAdmin): formfield_overrides = { models.TextField: {'widget': RichTextEditorWidget}, } 

注意在上面的外層字典中的鍵是一個實際的字段類,而不是字符串,對應的值又是一個字典;這些參數將被傳遞給form字段的__init__()方法。

警告:如果你想使用一個帶有關系字段的自定義widget。請確保你沒有在raw_id_fieldsradio_fields之中include那些字段的名字。

14. ModelAdmin.inlines

參考InlineModelAdmin對象,就像ModelAdmin.get_formsets_with_inlines()一樣。

15. ModelAdmin.list_display

指定顯示在修改頁面上的字段。這是一個很常用也是最重要的技巧之一。例如:

list_display = ('first_name', 'last_name')

如果你不設置這個屬性,admin站點將只顯示一列,內容是每個對象的__str__()(Python2使用__unicode__())方法返回的內容。

在list_display中,你可以設置四種值:

1.模型的字段名

class PersonAdmin(admin.ModelAdmin): list_display = ('first_name', 'last_name') 

2.一個函數,它接收一個模型實例作為參數

def upper_case_name(obj): return ("%s %s" % (obj.first_name, obj.last_name)).upper() upper_case_name.short_description = 'Name' class PersonAdmin(admin.ModelAdmin): list_display = (upper_case_name,) 

3.一個表示ModelAdmin的某個屬性的字符串

類似上面的函數調用,通過反射獲取函數名,換了種寫法而已,例如:

class PersonAdmin(admin.ModelAdmin): list_display = ('upper_case_name',) def upper_case_name(self, obj): return ("%s %s" % (obj.first_name, obj.last_name)).upper() upper_case_name.short_description = 'Name' 

4.一個表示模型的某個屬性的字符串

類似第二種,但是此處的self是模型實例,引用的是模型的屬性。參考下面的例子:

from django.db import models from django.contrib import admin class Person(models.Model): name = models.CharField(max_length=50) birthday = models.DateField() def decade_born_in(self): return self.birthday.strftime('%Y')[:3] + "0's" decade_born_in.short_description = 'Birth decade' class PersonAdmin(admin.ModelAdmin): list_display = ('name', 'decade_born_in') 

下面是對list_display屬性的一些特別提醒:

  • 對於Foreignkey字段,顯示的將是其__str__()方法的值。
  • 不支持ManyToMany字段。如果你非要顯示它,請自定義方法。
  • 對於BooleanField或NullBooleanField字段,會用on/off圖標代替True/False。
  • 如果給list_display提供的值是一個模型的、ModelAdmin的或者可調用的方法,默認情況下會自動對返回結果進行HTML轉義,這可能不是你想要的。

下面是一個完整的例子:

from django.db import models from django.contrib import admin from django.utils.html import format_html class Person(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) color_code = models.CharField(max_length=6) def colored_name(self): # 關鍵是這句!!!!!請自己調整縮進。 return '<span style="color: #%s;">%s %s</span>'%( self.color_code, self.first_name, self.last_name, ) class PersonAdmin(admin.ModelAdmin): list_display = ('first_name', 'last_name', 'colored_name') 

實際的效果如下圖所示:

6.png-88.2kB

很明顯,你是想要有個CSS效果,但Django把它當普通的字符串了。怎么辦呢?用format_html()或者format_html_join()或者mark_safe()方法!

from django.db import models from django.contrib import admin # 需要先導入! from django.utils.html import format_html class Person(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) color_code = models.CharField(max_length=6) def colored_name(self): # 這里還是重點,注意調用方式,‘%’變成‘{}’了! return format_html( '<span style="color: #{};">{} {}</span>', self.color_code, self.first_name, self.last_name, ) class PersonAdmin(admin.ModelAdmin): list_display = ('first_name', 'last_name', 'colored_name') 

下面看起來就會是你想要的結果了:

7.png-69.5kB

  • 如果某個字段的值為None或空字符串或空的可迭代對象,那么默認顯示為短橫杠“-”,你可以使用AdminSite.empty_value_display在全局改寫這一行為:
from django.contrib import admin admin.site.empty_value_display = '(None)' 

或者使用ModelAdmin.empty_value_display只改變某個類的行為:

class PersonAdmin(admin.ModelAdmin): empty_value_display = 'unknown' 

或者更細粒度的只改變某個字段的這一行為:

class PersonAdmin(admin.ModelAdmin): list_display = ('name', 'birth_date_view') def birth_date_view(self, obj): return obj.birth_date birth_date_view.empty_value_display = 'unknown' 
  • 默認情況下,一個返回布爾值的方法在list_display中顯示為True或者False的:

8.png-71.7kB

但如果你給這個方法添加一個boolean的屬性並賦值為True,它將顯示為on/off的圖標,如下圖:

from django.db import models from django.contrib import admin class Person(models.Model): first_name = models.CharField(max_length=50) birthday = models.DateField() def born_in_fifties(self): return self.birthday.strftime('%Y')[:3] == '195' # 關鍵在這里 born_in_fifties.boolean = True class PersonAdmin(admin.ModelAdmin): # 官方文檔這里有錯,將'name'改為'first_name' list_display = ('first_name', 'born_in_fifties') 

9.png-71kB

  • 通常情況下,在list_display列表里的元素如果不是數據庫內的某個具體字段,是不能根據它進行排序的。但是如果給這個字段添加一個admin_order_field屬性,並賦值一個具體的數據庫內的字段,則可以按這個字段對原字段進行排序,如下所示:
from django.db import models from django.contrib import admin from django.utils.html import format_html class Person(models.Model): first_name = models.CharField(max_length=50) color_code = models.CharField(max_length=6) def colored_first_name(self): return format_html( '<span style="color: #{};">{}</span>', self.color_code, self.first_name, ) # 就是這一句了! colored_first_name.admin_order_field = 'first_name' class PersonAdmin(admin.ModelAdmin): list_display = ('first_name', 'colored_first_name') 

本來colored_first_name是不能排序的,給它的admin_order_field賦值first_name后,就依托first_name進行排序了。

要降序的話,使用連字符“-”前綴:

colored_first_name.admin_order_field = '-first_name'

還可以跨表跨關系引用:

class Blog(models.Model): title = models.CharField(max_length=255) author = models.ForeignKey(Person, on_delete=models.CASCADE) class BlogAdmin(admin.ModelAdmin): list_display = ('title', 'author', 'author_first_name') def author_first_name(self, obj): return obj.author.first_name # 指定了另一張表的first_name作為排序的依據 author_first_name.admin_order_field = 'author__first_name' 
  • list_display里的元素還可以是某個屬性。但是請注意的是,如果使用python的@property方式來構造一個屬性,則不能給它添加short_description描述,只有使用property()函數的方法構造屬性的時候,才可以添加short_description描述,如下:
class Person(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) def my_property(self): return self.first_name + ' ' + self.last_name my_property.short_description = "Full name of the person" full_name = property(my_property) class PersonAdmin(admin.ModelAdmin): list_display = ('full_name',) 
  • list_display中的每個字段名在HTML中都將自動生成CSS類屬性,在th標簽中以column-<field_name>的格式,你可以通過它,對前端進行自定義或調整,例如設置寬度等等。
  • Django將按下面的順序,解釋list_display中的每個元素:
  • 模型的字段
  • 可調用對象
  • ModelAdmin的屬性
  • 模型的屬性

指定用於鏈接修改頁面的字段。通常情況,list_display列表中的第一個元素被作為指向目標修改頁面的超級鏈接點。但是,使用list_display_links可以幫你修改這一默認配置。

  • 如果設置為None,則根本沒有鏈接了,你無法跳到目標的修改頁面。
  • 或者設置為一個字段的元組或列表(和list_display的格式一樣),這里面的每一個元素都是一個指向修改頁面的鏈接。你可以指定和list_display一樣多的元素個數,Django不關系它的多少。唯一需要注意的是,如果你要使用list_display_links,你必須先有list_display

下面這個例子中first_namelast_name都可以點擊並跳轉到修改頁面。

class PersonAdmin(admin.ModelAdmin): list_display = ('first_name', 'last_name', 'birthday') list_display_links = ('first_name', 'last_name') 

而如果這樣,你將沒有任何鏈接:

class AuditEntryAdmin(admin.ModelAdmin): list_display = ('timestamp', 'message') list_display_links = None 

17. ModelAdmin.list_editable

這個選項是讓你指定在修改列表頁面中哪些字段可以被編輯。指定的字段將顯示為編輯框,可修改后直接批量保存,如下圖:

10.png-79.5kB

在這里,我們將last_name設置為了list_editable

需要注意的是:一是不能將list_display中沒有的元素設置為list_editable,二是不能將list_display_links中的元素設置為list_editable。原因很簡單,你不能編輯沒顯示的字段或者作為超級鏈接的字段。

18. ModelAdmin.list_filter

設置list_filter屬性后,可以激活修改列表頁面的右側邊欄,用於對列表元素進行過濾,如下圖:

11.png-37.3kB

list_filter必須是一個元組或列表,其元素是如下類型之一:

  • 某個字段名,但該字段必須是BooleanField、CharField、DateField、DateTimeField、IntegerField、ForeignKey或者ManyToManyField中的一種。例如:
class PersonAdmin(admin.ModelAdmin): list_filter = ('is_staff', 'company') 

在這里,你可以利用雙下划線進行跨表關聯,如下例:

class PersonAdmin(admin.UserAdmin): list_filter = ('company__name',) 
  • 一個繼承django.contrib.admin.SimpleListFilter的類。你要給這個類提供title和parameter_name的值,並重寫lookups和queryset方法。例如:
from datetime import date from django.contrib import admin from django.utils.translation import ugettext_lazy as _ class DecadeBornListFilter(admin.SimpleListFilter): # 提供一個可讀的標題 title = _('出生年代') # 用於URL查詢的參數. parameter_name = 'decade' def lookups(self, request, model_admin): """  返回一個二維元組。每個元組的第一個元素是用於URL查詢的真實值,  這個值會被self.value()方法獲取,並作為queryset方法的選擇條件。  第二個元素則是可讀的顯示在admin頁面右邊側欄的過濾選項。  """ return ( ('80s', _('80年代')), ('90s', _('90年代')), ) def queryset(self, request, queryset): """  根據self.value()方法獲取的條件值的不同執行具體的查詢操作。  並返回相應的結果。  """ if self.value() == '80s': return queryset.filter(birthday__gte=date(1980, 1, 1), birthday__lte=date(1989, 12, 31)) if self.value() == '90s': return queryset.filter(birthday__gte=date(1990, 1, 1), birthday__lte=date(1999, 12, 31)) class PersonAdmin(admin.ModelAdmin): list_display = ('first_name', 'last_name', "colored_first_name",'birthday') list_filter = (DecadeBornListFilter,) 

其效果如下圖:

12.png-98.7kB

注意:為了方便,我們通常會將HttpRequest對象傳遞給lookups和queryset方法,如下所示:

class AuthDecadeBornListFilter(DecadeBornListFilter): def lookups(self, request, model_admin): if request.user.is_superuser: return super(AuthDecadeBornListFilter, self).lookups(request, model_admin) def queryset(self, request, queryset): if request.user.is_superuser: return super(AuthDecadeBornListFilter, self).queryset(request, queryset) 

同樣的,我們默認將ModelAdmin對象傳遞給lookups方法。下面的例子根據查詢結果,調整過濾選項,如果某個年代沒有符合的對象,則這個選項不會在右邊的過濾欄中顯示:

class AdvancedDecadeBornListFilter(DecadeBornListFilter): def lookups(self, request, model_admin): """  只有存在確切的對象,並且它出生在對應年代時,才會出現這個過濾選項。  """ qs = model_admin.get_queryset(request) if qs.filter(birthday__gte=date(1980, 1, 1), birthday__lte=date(1989, 12, 31)).exists(): yield ('80s', _('in the eighties')) if qs.filter(birthday__gte=date(1990, 1, 1), birthday__lte=date(1999, 12, 31)).exists(): yield ('90s', _('in the nineties')) 
  • 也可以是一個元組。它的第一個元素是個字段名,第二個元素則是繼承了django.contrib.admin.FieldListFilter的類。例如:
class PersonAdmin(admin.ModelAdmin): list_filter = ( ('is_staff', admin.BooleanFieldListFilter), ) 

你可以使用RelatedOnlyFieldListFilter限制關聯的對象。假設author是關聯User模型的ForeignKey,下面的用法將只選擇那些出過書的user而不是所有的user:

class BookAdmin(admin.ModelAdmin): list_filter = ( ('author', admin.RelatedOnlyFieldListFilter), ) 

另外,其template屬性可以指定渲染的模板,如下則指定了一個自定義的模板。(Django默認的模板為admin/filter.html)

class FilterWithCustomTemplate(admin.SimpleListFilter): template = "custom_template.html" 

19. ModelAdmin.list_max_show_all

設置一個數值,當列表元素總數小於這個值的時候,將顯示一個“show all”鏈接,點擊后就能看到一個展示了所有元素的頁面。該值默認為200.

20. ModelAdmin.list_per_page

設置每頁顯示多少個元素。Django自動幫你分頁。默認為100。

如果設置了list_select_related屬性,Django將會使用select_related()方法查詢數據,這可能會幫助你減少一些數據庫訪問。

屬性的值可以是布爾值、元組或列表,默認為False。當值為True時,將始終調用select_related()方法;如果值為False,Django將查看list_display屬性,只對ForeignKey字段調用select_related()方法。

如果你需要更細粒度的控制,請賦值一個元組(或列表)。空元組將阻止select_related()方法,否則元組會被當做參數傳遞給select_related()方法。例如:

class ArticleAdmin(admin.ModelAdmin): list_select_related = ('author', 'category') 

這將會調用select_related('author', 'category')

22. ModelAdmin.ordering

設置排序的方式。

屬性的值必須為一個元組或列表,格式和模型的ordering參數一樣。如果不設置這個屬性,Django將按默認方式進行排序。如果你想進行動態排序,請自己實現get_ordering()方法。

23. ModelAdmin.paginator

指定用於分頁的分頁器。默認情況下,分頁器用的是Django自帶的django.core.paginator.Paginator。如果自定義分頁器的構造函數接口和django.core.paginator.Paginator的不一樣,那你還需要自己實現ModelAdmin.get_paginator()方法。

24. ModelAdmin.prepopulated_fields

設置預填充字段。不接收DateTimeField、ForeignKey和ManyToManyField類型的字段。

class ArticleAdmin(admin.ModelAdmin): prepopulated_fields = {"slug": ("title",)} 

25. ModelAdmin.preserve_filters

默認情況下,當你對目標進行創建、編輯或刪除操作后,頁面會依然保持原來的過濾狀態。將preserve_filters設為False后,則會返回未過濾狀態。

26. ModelAdmin.radio_fields

默認情況下,Django使用select標簽顯示ForeignKey或choices集合。如果將這種字段設置為radio_fields,則會以radio_box標簽的形式展示。下面的例子假設group是Person模型的ForeignKey字段,:

class PersonAdmin(admin.ModelAdmin): # 垂直布局。(肯定也有水平布局HORIZONTAL的啦) radio_fields = {"group": admin.VERTICAL} 

注意:不要將ForeignKey或choices集合之外的字段類型設置給這個屬性。

13.png-90.9kB

27. ModelAdmin.raw_id_fields

這個屬性會改變默認的ForeignKey和ManyToManyField的展示方式,它會變成一個輸入框,用於輸入關聯對象的主鍵id。對於ManyToManyField,id以逗號分隔。並且再輸入框右側提供一個放大鏡的圖標,你可以點擊進入選擇界面。例如:

class PersonAdmin(admin.ModelAdmin): raw_id_fields = ("group",) 

14.png-144.5kB

28. ModelAdmin.readonly_fields

該屬性包含的字段在頁面內將展示為不可編輯狀態。它還可以展示模型或者ModelAdmin本身的方法的返回值,類似ModelAdmin.list_display的行為。參考下面的例子:

from django.contrib import admin from django.utils.html import format_html_join from django.utils.safestring import mark_safe class PersonAdmin(admin.ModelAdmin): readonly_fields = ('address_report',) def address_report(self, instance): # assuming get_full_address() returns a list of strings # for each line of the address and you want to separate each # line by a linebreak return format_html_join( mark_safe('<br/>'), '{}', ((line,) for line in instance.get_full_address()), ) or mark_safe("<span class='errors'>I can't determine this address.</span>") # short_description functions like a model field's verbose_name address_report.short_description = "Address" 

29. ModelAdmin.save_as

默認情況下,它的值為False。如果設置為True,那么右下角的“Save and add another”按鈕將被替換成“Save as new”,意思也變成保存為一個新的對象。

16.png-95.7kB

30. ModelAdmin.save_as_continue

默認值為True, 在保存新對象后跳轉到該對象的修改頁面。但是如果這時save_as_continue=False,則會跳轉到元素列表頁面。

31. ModelAdmin.save_on_top

默認為False。 設為True時,頁面的頂部會提供同樣的一系列保存按鈕。

32. ModelAdmin.search_fields

設置這個屬性,可以為admin的修改列表頁面添加一個搜索框。

17.png-87kB

被搜索的字段可以是CharField或者TextField文本類型,也可以通過雙下划線進行ForeignKey或者ManyToManyField的查詢,格式為search_fields = ['foreign_key__related_fieldname'].

例如:如果作者是博客的ForeignKey字段,下面的方式將通過作者的email地址來查詢對應的博客,也就是email地址是查詢值的作者所寫的所有博客。

search_fields = ['user__email']

當你在搜索框里輸入一些文本的時候,Django會將文本分割成一個一個的關鍵字,並返回所有包含這些關鍵字的對象,必須注意的是,每個關鍵詞至少得是search_fields其中之一。例如,如果search_fields['first_name', 'last_name'],當用戶輸入John lennon時(注意中間的空格),Django將執行等同於下面的SQL語法WHERE子句:

WHERE (first_name ILIKE '%john%' OR last_name ILIKE '%john%') AND (first_name ILIKE '%lennon%' OR last_name ILIKE '%lennon%')

如果要執行更加嚴格的匹配或搜索,可以使用一些元字符,例如“^”。類似正則,它代表從開頭匹配。例如,如果search_fields['^first_name','^last_name'],當用戶輸入“John lennon”時(注意中間的空格),Django將執行等同於下面的SQL語法WHERE子句:

WHERE (first_name ILIKE 'john%' OR last_name ILIKE 'john%') AND (first_name ILIKE 'lennon%' OR last_name ILIKE 'lennon%')

也可以使用“=”,來進行區分大小寫的並絕對相等的嚴格匹配。例如,如果search_fields['=first_name','=last_name'],當用戶輸入“John lennon”時(注意中間的空格),Django將執行等同於下面的SQL語法WHERE子句:

WHERE (first_name ILIKE 'john' OR last_name ILIKE 'john') AND (first_name ILIKE 'lennon' OR last_name ILIKE 'lennon')

33. ModelAdmin.show_full_result_count

用於設置是否顯示一個過濾后的對象總數的提示信息,例如“99 results (103 total)”。如果它被設置為False,那么顯示的將是“ 99 results (Show all)”。 默認情況下,它的值為True,這將會對整個表進行一個count操作,在表很大的時候,可能會耗費一定的時間和資源。

34. ModelAdmin.view_on_site

這個屬性可以控制是否在admin頁面顯示“View site”的鏈接。這個鏈接主要用於跳轉到你指定的URL頁面。

18.png-25.1kB

屬性的值可以是布爾值或某個調用。如果是True(默認值),對象的get_absolute_url()方法將被調用並生成rul。

如果你的模型有一個get_absolute_url()方法,但你不想顯示“View site”鏈接,你只需要將view_on_site屬性設置為False。

from django.contrib import admin class PersonAdmin(admin.ModelAdmin): view_on_site = False 

如果屬性的值是一個調用,它將接收一個模型實例作為參數:

from django.contrib import admin from django.urls import reverse class PersonAdmin(admin.ModelAdmin): def view_on_site(self, obj): url = reverse('person-detail', kwargs={'slug': obj.slug}) return 'https://example.com' + url
ModelAdmin


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM