我有这些型号:
class UserProfile(models.Model):
name = models.CharField(max_length=100)
class Dialog(models.Model):
belong_to = models.ManyToManyField(UserProfile)
class Message(models.Model):
# Dialog to which this message belongs
part_of = models.ForeignKey(Dialog)
# User who sends message
sender = models.ForeignKey(UserProfile, related_name='sender')
# User who receives message
receiver = models.ForeignKey(UserProfile, related_name='receiver')
我想做的是限制发送方和接收方字段的选择,使它们只能是整个对话框所属的用户。我试过这个:
sender = models.ForeignKey(UserProfile,
related_name='sender',
limit_choices_to={'dialog':1})
这限制了选择,但仅限于id=1的对话的成员。我想知道这是否可以动态完成?
我不认为有任何方法可以像您想要的那样使用limit_choices_to进行动态筛选,因为您无法访问在那里形成这样一个查询所需的对象。
相反,您可能应该为消息创建自己的模型表单,并在那里为这些字段设置查询集。下面的内容。。。
class MessageForm(forms.ModelForm):
class Meta:
model = Message
def __init__(self, *args, **kwargs):
super(MessageForm, self).__init__(*args, **kwargs)
if self.instance.part_of and self.instance.part_of.id:
users = self.instance.part_of.belong_to.all()
self.fields['sender'].queryset = users
self.fields['receiver'].queryset = users
此外,为什么limit_choices_to
适用于您的示例,但在动态方面没有用处。
Django只是将limit_choices_to
表达式作为一个额外的过滤器来处理,以应用于ModelForm字段queryset。您的表达式{dialog: 1}
在语义上与将UserProfile.objects.filter(dialog=1)
的结果分配给我的示例中的查询集没有什么不同。
Django不知道具有该id的对话框是否作为关系存在于UserProfile中,它只是应用了过滤器。在这种情况下,存在一个id为1的对话框,因此它可以正常工作。如果你在你的例子中粘贴了一个无效的对话框id。。它将计算为一个空的查询集,并且您的表单中有0个选项。
它不能是动态的,因为在limit_choices_to
中,您只能为UserProfile模型创建一个筛选器表达式。您无法访问该字段所属的Message实例,也无法访问该消息所属的Dialog模型…因此,您无法创建筛选器来动态限制这些实例。
创建自己的ModelForm并限制那里的字段的查询集是正确的方法,因为那里有您需要的信息。
Django中没有办法动态过滤模型中的字段。为了确保没有用户输入错误的数据,我会编辑clean方法来执行额外的验证层。(因此,管理员可能认为他们可以添加任何发件人/收件人,但如果他们提交了一个不属于对话框用户的发件人/收件人的实例,则会出现验证错误。这将防止用户将不正确的数据添加到您网站外的数据库中。
然而,通过覆盖视图的相关表单的初始化方法,可以很容易地向您的网站添加过滤器(即视图本身)。
如果Django在模型字段中添加动态过滤器,那么创建网站就太容易了。
如果Message
的实例都属于一个Dialog
,为什么不在Dialog
模型上创建一个字段messages
?然后,您可以为每个Dialog
附加一个发送方和接收方。简而言之,大致如下:
class Dialog(models.Model):
messages = models.ManyToManyField(Message)
sender = models.ForeignKey(UserProfile)
receiver = models.ForeignKey(UserProfile)
class Message(models.Model):
# Other fields
消息的发送者和接收者总是对话框所属的那个些人。