文章目录
Admin定制: 创建–>注册
列表页定制
list_display = ('title',) # 显示的字段
list_filter = () # 过滤器
list_editable = ('auth',) # 可编辑字段
list_display_links = () # 可点击的链接字段
search_fields = ['title'] # 搜索框
list_per_page = 100 # 每页显示100条
list_max_show_all = 200
ordering = ['-weight'] # 负号表示降序排序
date_hierarchy = 'create_time' # 按时间分层
actions_on_top/bottom=True # 动作框在顶部显示
action_form = BookActionForm # ActionForm 追加动作输入框
list_select_related = False # 联表查询是否自动查询,可是布尔,列表或元组,如果是列表或元组,则级联查询指定的字段。注意:列表页默认点击第一个字段可进入编辑页面,该字段不能添加到 list_editable里面,否则会报错
show_full_result_count = True # 列表页模糊搜索后面显示的数据个数样式。True是显示条数,False时显示全部
# 自定义搜索选项
search_fields = ['author__first_name__iexact'] # 只能用于CharField或TextField
search_fields = ['^first_name', '^last_name'] # =区分大小写 ^从开头匹配 默认模糊匹配
search_fields = ['foreign_key__related_fieldname']
编辑页定制
form = forms.ModelForm # 为详情页指定form表单,可自定义显示的数据,字段
readonly_fields = () # 详情页面的只读字段
fields = None # 展示的字段
exclude = None # 详情页面排除的字段,字段可是数据库中的也可是自定义的
fieldsets = ((u'基础信息', {'fields': (('id', 'title'), 'book_set'),
"classes": ['collapse'] }), # 默认折叠收起
) # 跟fields互斥, 详情页面对数据进行分隔显示,对应到admin模板中的'fieldsets.html'
filter_vertical = () # M2M纵向展示
filter_horizontal = ('book_set', ) # M2M横向展示,多对多批量筛选
save_as = False
save_as_continue = True # 点击保存并继续编辑
save_on_top = False # save按钮位置, True则显示在页面上方
paginator = Paginator # 自定义分页类
preserve_filters = True
inlines = [] # 如果有FK到其他表,在详情页中可动态填加或删除级联数据
动作定制
# ModelAdmin
actions = ['search_books']
delete_selected.allowed_permissions = ('change',) # 动作权限。
模板定制
命令定制并传参
app/management/commands/XX.py
目录。执行命令python manage.py XX
。
class Command(BaseCommand):
def add_arguments(self, parser):
parser.add_argument('rank')
def handle(self, rank, *args, **options):
pass
Model
class Meta:
db_table = "book" # 默认app名_model名, 如publish_book
verbose_name = u"图书" # 编辑页
verbose_name_plural = verbose_name # 列表页
ModelAdmin方法重写
def delete_book(self, request, queryset):
# request.POST.get["author_id"]
# request.GET.get('author_id')
ids = [_.id for _ in queryset] # 选中的条目
self.message_user(request, u"删除成功", messages.SUCC)
delete_book.short_description = u"批量删除图书"
# 自定义动作:[自动检测是否选中条目, short_description/icon/type/style、confirm、 action_type/action_url]
# action_type: 0 =当前页面,1 = Simpleui新建选项卡,2 =浏览器新选项卡
def get_actions(self, request):
actions = super().get_actions(request)
if request.use.username != 'Doc.Li':
if 'delete_books' in actions:
del actions['delete_books']
return actions
def save_model(): # 保存按钮。修改保存时额外操作,如检查用户,校验参数等.
if 'book_set' in form.changed_data:
old_value = form.initial.get('book_set')
new_value = form.cleaned_data.get('book_set').all()
def change_view(self, request, object_id, extra_context=None):
pass
def changelist_view(self, request, extra_context=None): # 当前过滤条件键值对request.GET
pass
# 自定义显示表单:
def get_form(self, request, obj=None, **kwargs):
if request.user.is_superuser:
kwargs['form'] = MySuperuserForm
return super().get_form(request, obj, **kwargs)
# 自定义显示表单的ForeinKey字段
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == "author":
kwargs["queryset"] = Author.objects.filter(owner=request.user)
return super().formfield_for_foreignkey(db_field, request, **kwargs)
# 自定义显示表单的多对多字段
def formfield_for_manytomany(self, db_field, request, **kwargs):
pass
权限定制
def has_delete_permission(self, request, obj=None): # 删除权限
return true if request.user.is_superuser else false
def get_search_results(self, request, queryset, search_term): # 列表页输入框搜索
# 【根据关键字/过滤器进行查询集合】设置规则search_term.startswith('$')
distinct = False
return queryset, distince
def get_queryset(self, request): # 列表页QuerySet集
# 根据用户权限、request.path,同一个sql表不同展示(如节目、应用节目)。
pass
ModelForm定制
from ajax_select import make_ajax_field
book_set = make_ajax_field(Author, 'book_set', 'book', help_text=u"输入关键词搜索")
book_set = forms.ModelMultipleChoiceField(label="图书", widget=forms.CheckboxSelectMultiple,
queryset= Book.objects.filter(publish=True))
desc = forms.CharField(label=u"描述", required=False, max_length=64,
widget=forms.TextInput(attrs={'style': 'width: 500px;'}))
class Meta:
model = Author
widget = {
'desc': forms.Textarea(attrs={'cols': 80, 'rows': 5}),
}
exclude = []
其他
pip install opencv-python==4.2.0.32 -i http://pyp --trusted-host XXX
# 图片展示
s = '<a target=_blank href="%s"><img style="height:88px" src="%s"/></a>' % (url, url)
模板定制
如何美化Django的admin??默认的django模板是放在contrib/admin/templates/admin目录下的。
Model或ModelAdmin的方法属性或一个可调用函数:
Names of model and model admin methods will only be used if they’re listed in readonly_fields.
[列表页可以,编辑页要放在readonly_fields里??]
否则报错FieldError:Unknown field(s) specified for Author. Check fields/fieldsets/exclude attributes of class AuthorAdmin.
myMethod.boolean = True # 返回True或False,这样页面上会展示on或者off图标。
myMethod.short_description = "Full name of the person"
age.admin_order_field = 'birthday'
# admins.py: 动作命令,不需要加入readonly_fields
# models.py: 字段。 需要加入readonly_fields
readonly_fields = ['myMethod']
利用 Session 实现自动登录
https://www.jianshu.com/p/3dafba4d1cda
urlpatterns = [
path('ajax_select/', include(ajax_select_urls)),
path('admin/lookups/', include(ajax_select_urls)),
path('admin/', admin.site.urls), # admin.site.register(Author, AuthorAdmin)
]
INSTALLED_APPS = [
'simpleui',
'django.contrib.auth',
'django.contrib.sessions',
'django_cleanup', # 记录删除时清理相关文件和和图片
]
MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware',
]
因为需要 Cookie 功能,所以同样需要在 settings.py 增加一些配置。如果你将 SESSION_SAVE_EVERY_REQUEST 设置为 True, 那么关闭浏览器之后,需要重新登录。
SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key
SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认)
SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认)
SESSION_COOKIE_SECURE = False # 是否Https传输cookie
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认)
SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默认)
SESSION_SAVE_EVERY_REQUEST = False # 是否设置关闭浏览器使得Session过期
SESSION_COOKIE_AT_BROWSER_CLOSE = False # 是否每次请求都保存Session,默认修改之后才能保存
# 让用户会话长时间无活动而失效
SESSION_EXPIRE_AT_BROWSER_CLOSE = TRUE
class SessionExpiredMiddleware:
def process_request(request):
last_activity = request.session['last_activity']
now = datetime.now()
if(now - last_activity).minutes > 10:
return HttpResponseRedirect("LONIN_PAGE_URL")
if not request.is_ajax():
request.session['last_activity'] = datetime.now()