在ModelForm中手动设置模型字段 [英] Manually set model fields in ModelForm

查看:52
本文介绍了在ModelForm中手动设置模型字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有外键和唯一约束的模型,如下所示:

I have a model with a foreign key and a unique constraint as follows:

class Menu(models.Model):
    tournament = models.ForeignKey(Tournament, on_delete=models.CASCADE)
    name = models.CharField(max_length=128)
    date_menu = models.DateField()

    class Meta:
        constraints = [
            models.UniqueConstraint(fields=['tournament', 'name', 'date_menu'], name="unique_name_menu")
        ]

我想创建一个表单来添加Menu实例.但是,比赛的值由页面的URL设置.我不希望用户能够设置它.

I would like to create a form to add instance of Menu. However the value of tournament is set by the URL of the page. I do not want the user to be able to set it.

为此,我使用了modelForm,但不包括比赛字段:

For this I use a modelForm, excluding the tournament field :

class MenuForm(forms.ModelForm):

    date_menu = forms.DateField(initial=datetime.datetime.now())

    class Meta:
        model = Menu
        exclude = ['tournament']

这是我的观点:

def add_menu(request, tournament_slug):
    tournament = get_object_or_404(Tournament, slug=tournament_slug)
    form = MenuForm(request.POST or None)
    
    if form.is_valid():
        menu_id = form.save(commit=False)
        menu_id.tournament = Tournament.objects.get(pk=1)
        menu_id.save()  # I get the integrity error only here

        return HttpResponseRedirect(reverse('admin'))

    return render(request, "view.html", {'form': form, 'formset': formset, "tournament": tournament})

我的问题是,当我在此表单上调用 .is_valid()函数时,由于未设置比赛字段,因此无法检查唯一性条件.结果,在视图中调用save函数时出现完整性错误.

My problem is that when I call the .is_valid() function on this form the uniqueness condition cannot be checked as the tournament field is not set. As a result I get an integrity error when calling the save function in the view.

问题是:在检查表单实例是否有效之前,如何链接由表单创建的Menu实例以添加比赛字段?如果这不是正确的方法,该如何检查模型实例的唯一性,并在需要时将相应的错误返回给模板?

The question is : how can link the Menu instance created by the form to add the tournament field before checking if it's valid? If it's not the right way of doing it, how can I check the uniqueness of the model instance and return the corresponding errors to the template when needed?

我尝试将锦标赛字段作为隐藏字段包含在视图中,它可以工作,但是我不知道这是否是最好的方法...

I tried including the tournament field as hidden field in the view, it works but I don't know if that's the best way of doing it...

推荐答案

您应该简单地使用未保存的 Menu 实例实例化表单,这样您的视图应类似于:

You should simply instantiate the form with an unsaved instance of Menu so your view should be like:

def add_menu(request, tournament_slug):
    tournament = get_object_or_404(Tournament, slug=tournament_slug)
    if request.method == 'POST':
        form = MenuForm(request.POST, instance=Menu(tournament=tournament))
        if form.is_valid():
            menu_id = form.save()
            return HttpResponseRedirect(reverse('admin'))
    else:
        form = MenuForm(instance=Menu(tournament=tournament))
    return render(request, "view.html", {'form': form, "tournament": tournament})

此表单还会调用 _get_validation_exclusions(),并将表单中不存在的字段从验证中排除.您可以尝试覆盖 validate_unique 来克服此问题:

Also the form calls _get_validation_exclusions() and excludes fields not present in the form from validation. You can try to override validate_unique to overcome this:

class MenuForm(forms.ModelForm):

    date_menu = forms.DateField(initial=datetime.datetime.now())

    class Meta:
        model = Menu
        exclude = ['tournament']
    
    def validate_unique(self):
        exclude = self._get_validation_exclusions()
        if 'tournament' in exclude:
            exclude.remove('tournament') # Make sure `tournament` gets validated
        try:
            self.instance.validate_unique(exclude=exclude)
        except ValidationError as e:
            self._update_errors(e)

注意:我更改了视图结构,以避免使用 MenuForm(request.POST或None)(这是反模式).(形式即使在POST数据中什么也没发送的情况下,它仍然可以有效您编写的此类表格将被视为无效).

Note: I changed your view structure to avoid using MenuForm(request.POST or None) which is an antipattern. (Forms can be valid even if nothing is sent in the POST data, with the way you write such forms would be considered invalid).

编辑:如评论中所述,隐藏和禁用字段的选择可能比覆盖表单 validate_unique 方法要好得多:

Edit: As discussed in the comments perhaps the option of a hidden and disabled field is much better than overriding the forms validate_unique method:

class MenuForm(forms.ModelForm):
    tournament = forms.ModelChoiceField(
        queryset=Tournament.objects.all(),
        widget=forms.HiddenInput(),
        disabled=True
    )
    date_menu = forms.DateField(initial=datetime.datetime.now())

    class Meta:
        model = Menu
        fields = ['tournament', 'name', 'date_menu']

这篇关于在ModelForm中手动设置模型字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆