在Django基础(19): Django Admin管理后台详解(上)中小编我介绍了如何创建superuser,如何自定义数据表的显示选项(list_display, list_filter, list_per_page, list_editable, ordering),如何更好地显示单对多(raw_id_fields)和多对多关系(filter_horizontal),如何使用Inlines显示多张数据表在同一页面上。今天我们来看下django admin的一些高级技巧,比如如何重写django admin的save方法和get_queryset方法。
重写Django admin的save_model方法
很多时候,我们需要重写Django自带的save_model方法。比如在文章创建时我们希望在后台自动添加作者,而不是允许用户自己选择作者是谁,我们可以选择在创建文章的表单里把作者隐藏,而在后台添加作者。如下所示:
from django.contrib import admin
class ArticleAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
obj.author = request.user
super().save_model(request, obj, form, change)
在我们世界那么大,我想去看看。Django仿制微信朋友圈九宫格相册(1)一文中我们也展示了save_model方法的重写,该方法作用是允许用户在创建Album对象时,还上传一个zip文件包。上传后对zip文件包进行解压存储,并与每个Image对象想关联。
# album/forms.py
from django import forms
from .models import Album
class AlbumForm(forms.ModelForm):
class Meta:
model = Album
exclude = []
zip = forms.FileField(required=False)
# album/admin.py
import os
import uuid
import zipfile
from django.contrib import admin
from django.core.files.base import ContentFile
from .models import Album, AlbumImage
from .forms import AlbumForm
@admin.register(Album)
class AlbumModelAdmin(admin.ModelAdmin):
form = AlbumForm
prepopulated_fields = {'slug': ('title',)}
list_display = ('title', 'thumb')
list_filter = ('create_date',)
def save_model(self, request, obj, form, change):
if form.is_valid():
album = form.save()
if form.cleaned_data['zip'] is not None:
zip = zipfile.ZipFile(form.cleaned_data['zip'])
for filename in sorted(zip.namelist()):
file_name = os.path.basename(filename)
if not file_name:
continue
data = zip.read(filename)
contentfile = ContentFile(data)
img = AlbumImage()
img.album = album
filename = '{0}{1}.jpg'.format(album.slug[:8], str(uuid.uuid4())[-13:])
img.alt = filename
img.image.save(filename, contentfile)
img.thumb.save('thumb-{0}'.format(filename), contentfile)
img.save()
zip.close()
super().save_model(request, obj, form, change)
还记得我们Django 2.0 项目实战: 扩展Django自带User模型,实现用户注册与登录中对django的User模型做的扩展吗?我们新建了一个UserProfile模型,其与User是一对一的关系。我们现在希望在admin中创建一个User对象时,也同时创建一个UserProfile对象,这时我们就需要用到save_model方法的重写了。代码如下所示:
#myaccount/admin.py
from django.contrib import admin
from django.contrib.auth.models import User
from django.contrib.auth.admin import UserAdmin
from .models import UserProfile
admin.site.unregister(User)
class UserProfileInline(admin.StackedInline):
model = UserProfile
exclude = ["uid", "join_date", "mod_date"]
class UserAdmin(UserAdmin):
inlines = [UserProfileInline, ]
def save_model(self, request, obj, form, change):
if form.is_valid():
user = form.save()
user_profile = UserProfile()
user_profile.user = user
user_profile.save()
super().save_model(request, obj, form, change)
class UserProfileAdmin(admin.ModelAdmin):
list_display = ('user', 'avatar', 'org', 'join_date')
exclude = []
ordering = ('-join_date',)
admin.site.register(User, UserAdmin)
admin.site.register(UserProfile, UserProfileAdmin)
展示效果如下。我们使用了Inlines使UserProfile与User展示在同一页面上。由于我们重写了save_model方法,这样可以自动在创建User时也创建UserProfile,避免了只创建User而未创建UserProfile的错误,这对1对1的关系非常重要。
重写Django admin的get_queryset方法
Django的admin默认会展示所有对象。通过重写get_queryset方法,我们可以控制所需要获取的对象。比如下例中,我们先对用户进行判定,如果用户是超级用户就展示所有文章,如果不是超级用户,我们仅展示用户自己所发表的文章。
class ArticleAdmin(admin.ModelAdmin):
def get_queryset(self, request):
qs = super().get_queryset(request)
if request.user.is_superuser:
return qs
return qs.filter(author=request.user)
小结
本文总结了django admin的一些高级技巧,比如如何自定义list_display和list_filter, 以及如何重写django admin的save方法和get_queryset方法。这些方法和技巧都非常有用,要熟练掌握哦。下文将是django admin介绍的最后一篇,小编我将介绍下如何美化django-admin,欢迎关注。
大江狗
2018.11.3
Django Web开发核心基础知识
Django网站开发四件套是如何遵循MVC软件设计模式的?
Django基础核心技术介绍(1): Model模型的介绍与设计
Django基础核心技术介绍(2): URL的设计与配置
Django基础核心技术介绍(3): View视图详解与通用视图
Django基础核心技术介绍(4): Template模板的编写及过滤器
Django基础核心结束介绍(5): Forms表单的使用与设计
Django基础(6): 模型Models高级进阶必读。
Django基础(7): cookie和session应用场景及如何使用
Django基础(8): 缓存Cache应用场景及工作原理,Cache设置及如何使用
Django基础(9): 表单Forms的高级使用技巧
Django基础(10): URL重定向的HttpResponseDirect, redirect和reverse的用法
Django基础(11): 表单集合Formset的高级用法
Django基础(12): Request对象详解及开发显示用户IP地址和浏览器APP
Django基础(13): 深夜放干货。QuerySet特性及高级使用技巧,如何减少数据库的访问,节省内存,提升网站性能。
Django基础(14): 通过next参数实现登录后跳转回到前一页的3种方法
Django基础(15): 模板过滤器(filter)的工作原理及如何自定义模板过滤器
Django基础(16): 模板标签(tags)的分类及如何自定义模板标签
Django基础(17): 如何上传处理文件及Ajax文件上传示范(附GitHub源码)
Django基础(18): 实现文件下载的3种方法及文件私有化
Django基础(19): Django Admin管理后台详解(上)
Django基础(20): Django admin管理后台详解(中)如何自定义list_display和list_filter
Django基础(21): Django admin管理后台详解(下)如何自定义actions, 表单和美化admin
Django基础(22): 数据库的设计之自定义表名,建立索引和使用多数据库主从配置
Django基础(23): 权限管理(permissions)与用户组(group)详解
Django基础(24): aggregate和annotate方法使用详解与示例
Django基础(25):settings.py设置选项深入解读。大江狗精品原创。
Django基础(26): 常用装饰器应用场景及正确使用方法
Django基础(27): 快捷函数(shortcut function)模块详解Django基础(28): 如何设计充满陷阱的优美URL
Django基础(28): 如何设计充满陷阱的优美URL
Django Web开发实战案例
Django 2.0 项目实战(1): 扩展Django自带User模型,实现用户注册与登录
Django 2.0 项目实战(2): 编辑用户个人资料,扩展Django后台UserAdmin
Django 2.0项目实战(3): 密码重置与退出登录
Django 2.0 项目实战: 图片上传与显示
Django 2.0 项目实战: PDF文件页面提取
Django 2.0 项目实战: PDF文件合并
Django 2.0 项目实战:输出树形分类目录
Django 2.0 项目实战: 网页计数器统计浏览次数
Django 2.0 项目实战: 利用AJAX实现博文实时搜索
Django 1.X和2.0下利用自带分页Paginator类实现分页功能
Django实战: 利用Ajax生成联动下拉菜单
世界那么大,我想去看看。Django仿制微信朋友圈九宫格相册(1)
世界那么大,我想去看看。Django仿制微信朋友圈九宫格相册(2)
django-allauth教程(1): 安装,用户注册,登录,邮箱验证和密码重置(更新)
django-allauth教程(2): 用户个人资料UserProfile扩展与编辑
django-allauth教程(3): 第三方账户授权登录(以百度账号为例)
django-allauth教程(4): 美化模板,自定义邮件和消息内容
Django+jQuery cropper实现用户头像裁剪, 预览和上传[原创]
Django实战教程: 开发餐厅在线点评网站(1)
Django实战教程: 开发餐厅在线点评网站(2)
Django实战教程: 开发企业级应用智能文档管理系统smartdoc(1)
Django实战教程: 开发企业级应用智能文档管理系统smartdoc(2)之权限管理
Django实战教程: 开发企业级应用智能文档管理系统smartdoc(3)附GitHub代码地址
Django实战专题: 开发专业博客(1)之内容管理后台开发
Django实战专题: 开发专业博客(2)之母子类别导航和添加富文本编辑器CKEditor
Django实战专题: 开发专业博客(3)之仿微信评论点赞功能
Django实战: Python爬取链家上海二手房信息,存入数据库并在前端显示
Django应用实战: 编写你自己的PDF编辑器, 实现PDF页面提取, 页面合并与替换。
如何在阿里云Ubuntu服务器通过uWSGI和Nginx部署Django项目教程-大江狗原创出品
Django Web开发学习笔记
浅谈Django Model创建对象的save与create方法
Django模板设置全局变量(默认变量)
Django常用命令django-admin.py和manage.py用法详解
Django自定义图片和文件上传路径(upload_to)的2种方式
Django ContentTypes框架详解及使用场景介绍
Django更改模型过程中易出现的问题及解决方案
2019新年第一篇: SQLite的优缺点及Django配置MySQL数据库