如何重写Django Admin的save_model方法和get_queryset方法

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_quer
  • 2
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值