【问题标题】:How do I extend a Django admin form's clean() function?如何扩展 Django 管理表单的 clean() 函数?
【发布时间】:2021-06-10 12:12:01
【问题描述】:

我有一个 Django 3.0 模型和相关的管理员添加表单。我想验证输入的数据与同时输入的其他数据,就像普通表单一样——例如,确保两个密码字段匹配,或者确保电子邮件和备用电子邮件字段不同。

似乎最好的方法是为添加页面的表单扩展clean() 函数,因为这是您用于普通表单的函数。该文档似乎暗示这可能是可能的,但它没有提供足够的信息来将它们放在一起。 Web 搜索“Django 扩展管理表单”返回结果仅用于扩展模板。

如何扩展 Django Admin Add Form 的 clean() 函数?

编辑:为了具体起见,这里有一个模型和模型管理员的例子,答案应该适用于:

# models.py

class Questions(models.Model):
    question = models.CharField(
        help_text='Text of question'
    )

class Choices(models.Model):

    q = models.ForeignKey(
        Questions,
        on_delete=models.CASCADE
    )
    choice = models.CharField(
        help_text='Text of choice'
    )
# admin.py

class ChoicesInQuestions(admin.TabularInline):
    model = Choices
    extra = 4
    max_num = 4

@admin.register(Questions)
class QuestionAdmin(admin.ModelAdmin):

    inlines = [ChoicesInQuestions]

问题添加页面上有四个选项。我想在提交时同时对它们进行相互验证,就像我可以使用其 clean() 函数对任何常规表单进行操作一样。

【问题讨论】:

    标签: django django-admin


    【解决方案1】:

    经过作者的一些澄清,这里有一个问题的解决方案:如何在BaseInlineFormSetform 上编写自定义验证。 (上一个问题是如何扩展 Django 管理表单的 clean() 函数?)

    解决方案

    class InlineFormset(forms.models.BaseInlineFormSet):
    
        def clean(self):
            choice1 = self.cleaned_data[0].get('choice')
            choice2 = self.cleaned_data[1].get('choice')
            choice3 = self.cleaned_data[2].get('choice')
            choice4 = self.cleaned_data[3].get('choice')
    
            if "please_give_me_an_error" in choice1:
                raise ValidationError('Error!!!')
    
    
    class ChoicesInQuestions(admin.TabularInline):
        model = Choices
        extra = 4
        max_num = 4
        formset = InlineFormset
    
    @admin.register(Questions)
    class QuestionAdmin(admin.ModelAdmin):
        inlines = [ChoicesInQuestions]
    

    演示

    ------------------初始响应--------------- ---------------

    请记住,可以存在两种类型的验证。您可以在backend 上进行验证(或者您必须),并且您可以在frontend 上强制执行UserInterface/UserExperience 验证。可能有一个或两个

    在 django 后端验证

    可能你还没有达到具体的documentation place (我输入了文档中的示例默认数据)

    你必须:

    1. 创建特定的 modelForm(用于 email 和 email_backup)
    class PersonForm(forms.ModelForm):
    
        def clean(self):
            cleaned_data = super().clean()
            email = cleaned_data.get("email")
            email_backup = cleaned_data.get("email_backup")
    
            if email and email_backup:
                # Only do something if both fields are valid so far.
                if email != email_backup:
                    raise ValidationError(
                        "Email and email backup aren't equal "
                        "Verify."
                    )
    
        class Meta:
            model = Person
            exclude = ['name']
    
    1. 将特定表单覆盖为ModelAdmin
    from myapp.forms import PersonForm
    
    class PersonAdmin(admin.ModelAdmin):
        form = PersonForm
    
    1. 去吧!

    使用 javascript 在前端验证

    这加强了用户体验,并会减少对服务器的请求...有趣...但它需要大量的集成时间。

    在modeladmin中追加js,并写一些js!

    class MyModelAdmin(admin.ModelAdmin):
        class Media:
            js = ('js/admin/mymodel.js',)
    

    有一些 js 工具包可以满足这种需求,例如 FormValidationParsley。最后一个有django integration(但有点不维护)

    【讨论】:

    • 感谢您的详尽回复!不过,这并不是我真正要问的。在您的“后端”示例中,我必须编写一个全新的表单。复制已经存在的东西需要做很多工作,而且我只能做比已经存在的版本更糟糕的工作。难道我不能获取现有的ModelAdmin 表单并使用它,而是对其clean() 函数进行更改吗?
    • 如果你愿意,编辑你的问题,附上你的模型,我会编辑答案。
    • 我添加了一个示例 Model 和 ModelAdmin
    • 谢谢达里恩!尝试给定的解决方案是否适合您!在这种情况下,我会很感激一个成功的检查点击!
    • 原谅延迟,我不得不花一个月的时间重建我的数据库,因为 Django,我才能回到这个。感谢您的工作,但请注意我没有改变我的问题。我想知道如何扩展现有的clean() 函数。在这种情况下,您似乎建议我使用新的 clean() 函数定义一个新表单,这不一样。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-12
    • 1970-01-01
    • 1970-01-01
    • 2016-10-10
    • 1970-01-01
    • 2014-11-03
    • 2017-04-10
    相关资源
    最近更新 更多