Django ModelForms:将ManyToMany字段显示为单选 [英] Django ModelForms: Display ManyToMany field as single-select

查看:158
本文介绍了Django ModelForms:将ManyToMany字段显示为单选的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Django应用中,我有一个模型Bet,其中包含与Django的User模型的ManyToMany关系:

  class Bet(models.Model):
...
参与者= models.ManyToManyField(用户)

用户应该可以使用表单开始新的投注。直到现在,投注只有两个参与者,其中一个是自己创建投注的用户。这意味着在新赌注的形式下,您必须选择一个参与者。在保存表单数据时,投注创建者被添加为参与者。



我正在使用ModelForm为我的 NewBetForm

  class NewBetForm(forms.ModelForm):
class Meta:
model = Bet
widgets = {
'Particip':forms.Select()
}

def save(self,user):
...#将用户保存为参与者

注意参与者字段的重新定义的小部件,确保您只能选择一个参与者。 p>

但是,这给我一个验证错误:

 输入一个值。 

我不太确定这来自哪里。如果我在开发者工具中查看POST数据,似乎与使用默认窗口小部件并仅选择一个参与者完全相同。但是,似乎ManyToManyField的 to_python()方法对此数据有问题。至少没有创建用户对象,如果我启用选择小部件。



我知道我可以解决这个问题,从表单中排除参与者字段并自己定义但是如果仍然可以使用ModelForm的容量(毕竟它只是一个小部件的更改),那将会更好一些。也许我可以以某种方式操纵传递的数据,如果我知道如何。



任何人都可以告诉我问题是什么,如果有一个很好的解决方法?



提前感谢!



修改



如意见中的建议:视图的(相关)代码。

  def new_bet(request )
如果request.method =='POST':
form = NewBetForm(request.POST)
如果form.is_valid():
form.save(request.user )
...#成功消息和重定向
else:
form = NewBetForm()
return render(request,'bets / new.html',{'form' form})


解决方案

在挖掘Django代码后,我可以回答我自己的问题。



问题是Django的ModelForm将模型中的 ManyToManyField 映射到 ModelMultipleChoiceField s e形式。这种表单字段期望窗口小部件对象从其 value_from_datadict()方法返回一个序列。 ModelMultipleChoiceField (即 SelectMultiple )的默认小部件覆盖 value_from_datadict()从用户提供的数据返回一个列表。但是,如果我使用选择小部件,则使用超类的默认 value_from_datadict()方法,它只返回一个串。 ModelMultipleChoiceField 根本不喜欢,因此验证错误。



对于我可以想到的解决方案: / p>


  1. 覆盖 value_from_datadict() 选择通过继承或一些类装饰器。

  2. 通过创建新的表单字段并调整 save() ModelForm 的$ c>方法将其数据保存在m2m关系中。

秒解决方案似乎不那么冗长,所以这就是我将要做的。


In a Django app, I'm having a model Bet which contains a ManyToMany relation with the User model of Django:

class Bet(models.Model):
    ...
    participants = models.ManyToManyField(User)

User should be able to start new bets using a form. Until now, bets have exactly two participants, one of which is the user who creates the bet himself. That means in the form for the new bet you have to chose exactly one participant. The bet creator is added as participant upon saving of the form data.

I'm using a ModelForm for my NewBetForm:

class NewBetForm(forms.ModelForm):
    class Meta:
        model = Bet
        widgets = {
            'participants': forms.Select()
        }

    def save(self, user):
        ... # save user as participant

Notice the redefined widget for the participants field which makes sure you can only choose one participant.

However, this gives me a validation error:

Enter a list of values.

I'm not really sure where this comes from. If I look at the POST data in the developer tools, it seems to be exactly the same as if I use the default widget and choose only one participant. However, it seems like the to_python() method of the ManyToManyField has its problems with this data. At least there is no User object created if I enable the Select widget.

I know I could work around this problem by excluding the participants field from the form and define it myself but it would be a lot nicer if the ModelForm's capacities could still be used (after all, it's only a widget change). Maybe I could manipulate the passed data in some way if I knew how.

Can anyone tell me what the problem is exactly and if there is a good way to solve it?

Thanks in advance!

Edit

As suggested in the comments: the (relevant) code of the view.

def new_bet(request):
    if request.method == 'POST':
        form = NewBetForm(request.POST)
        if form.is_valid():
            form.save(request.user)
            ... # success message and redirect
    else:
        form = NewBetForm()
    return render(request, 'bets/new.html', {'form': form})

解决方案

After digging in the Django code, I can answer my own question.

The problem is that Django's ModelForm maps ManyToManyFields in the model to ModelMultipleChoiceFields of the form. This kind of form field expects the widget object to return a sequence from its value_from_datadict() method. The default widget for ModelMultipleChoiceField (which is SelectMultiple) overrides value_from_datadict() to return a list from the user supplied data. But if I use the Select widget, the default value_from_datadict() method of the superclass is used, which simply returns a string. ModelMultipleChoiceField doesn't like that at all, hence the validation error.

To solutions I could think of:

  1. Overriding the value_from_datadict() of Select either via inheritance or some class decorator.
  2. Handling the m2m field manually by creating a new form field and adjusting the save() method of the ModelForm to save its data in the m2m relation.

The seconds solution seems to be less verbose, so that's what I will be going with.

这篇关于Django ModelForms:将ManyToMany字段显示为单选的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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