详解Django的 get_form_class() 函数:获取视图所使用的表单类

  • Post category:Python

get_form_class()函数是Django中的一个方法,主要用于自定义Admin中表单的配置。当Admin的配置中使用了formformfield_overrides字段时,Django会自动调用get_form_class()方法来获取表单类。这个方法的作用就是返回一个表单类,该表单类将被用来在Admin中管理相应的数据模型。

以下是get_form_class()方法的调用方式:

class MyModelAdmin(admin.ModelAdmin):
    form = MyCustomForm # 调用MyCustomForm定义的自定义表单

    def get_form_class(self, request, obj=None, **kwargs):
        """
        获取表单类的方法。
        :param request: HttpRequest对象。
        :param obj: 当前编辑对象。
        :param kwargs: 其他可选参数。
        :return: 一个表单类。
        """
        if obj is None:
            return MyAddForm # 创建新纪录时调用MyAddForm定义的表单。
        else:
            return MyEditForm # 编辑已有纪录时调用MyEditForm定义的表单。

其中request参数是当前请求的HttpRequest对象,obj参数用于表示当前编辑的对象实例。当创建新的对象实例时,objNone,否则obj为对应的数据库对象实例。

以下是两个使用get_form_class()方法的实例:

  1. 根据用户类型生成不同的表单类

假设我们的网站有两种用户类型:普通用户和管理员用户。普通用户只能够对自己的个人信息进行编辑,而管理员用户可以编辑所有用户的信息。因此,我们需要根据当前登录的用户类型来生成不同的表单类:

from django.contrib.auth.decorators import login_required, user_passes_test
from django.contrib.admin.views.decorators import staff_member_required
from django.utils.decorators import method_decorator
from django.forms import ModelForm

class UserProfileForm(ModelForm):
    class Meta:
        model = UserProfile

class AdminUserProfileForm(ModelForm):
    class Meta:
        model = UserProfile

class UserProfileAdmin(admin.ModelAdmin):
    model = UserProfile

    def get_form_class(self, request, obj=None, **kwargs):
        user = request.user

        if user.has_perm('auth.change_user'):
            return AdminUserProfileForm

        return UserProfileForm

    @method_decorator(login_required)
    @method_decorator(user_passes_test(lambda u: u.is_staff))
    def changelist_view(self, request, extra_context=None):
        return super().changelist_view(request, extra_context)

    @method_decorator(login_required)
    @method_decorator(staff_member_required)
    def add_view(self, request, extra_context=None):
        return super().add_view(request, extra_context)

在这个例子中,我们定义了两个表单类:UserProfileFormAdminUserProfileForm。前者用于普通用户,后者用于管理员用户。通过user.has_perm('auth.change_user')判断当前用户是否有权限对所有用户信息进行修改。如果有,返回AdminUserProfileForm,否则返回普通用户表单类UserProfileForm

另外,在视图函数中我们使用了Django的登录装饰器和user_passes_test装饰器来限制用户访问权限。login_required装饰器用于限制必须登录才能访问changelist_viewadd_view方法。

  1. 实现联动表单

假设我们的网站有一个需求:在编辑某个页面时,需要根据当前选中的一级分类,动态生成对应的二级分类下拉框。此时我们就可以使用get_form_class()方法来实现这个需求:

class ProductForm(ModelForm):
    class Meta:
        model = Product

class ProductAdmin(admin.ModelAdmin):
    form = ProductForm

    def get_form_class(self, request, obj=None, **kwargs):
        form_class = super().get_form_class(request, obj, **kwargs)

        class MyProductForm(form_class):
            def __init__(self, *args, **kwargs):
                super().__init__(*args, **kwargs)
                self.fields['category2'].widget.choices = self.get_category2_choices()

            def get_category2_choices(self):
                """
                动态生成category2下拉框的选项。
                """
                if self.instance is None or self.instance.category is None:
                    return []

                return ((c.id, c.name) for c in self.instance.category.category2_set.all())

        return MyProductForm

在这个例子中,我们首先定义了一个ProductForm表单类。在get_form_class()方法中,我们首先调用super()方法来获取原始的表单类。然后定义一个内部类MyProductForm继承原始的表单类。在MyProductForm中,我们重写了__init__()方法,在方法中动态设置了二级分类下拉框的选项。

重要的是,我们在获取数据集的时候使用了ORM的链式查询。最终返回的选择元组是一个迭代器。