基于同一模型中的另一个外键,动态限制Django模型中Foreignkey的选择

时间:2015-03-25 12:34:14

标签: python django django-models foreign-keys

我有这些模特:

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的对话框成员。我想知道这是否可以动态完成?

2 个答案:

答案 0 :(得分:5)

我不相信有任何方法可以使用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字段查询集。您的表达式{dialog: 1}在语义上与您在我的示例中将UserProfile.objects.filter(dialog=1)的结果分配给查询集时没有什么不同。

Django不知道具有该id的对话是否作为UserProfile上的关系存在,它只是应用了过滤器。在这种情况下,存在一个id为1的对话框,因此它可以解决问题。如果您在示例中粘贴了无效的对话框ID,那么它将评估为空的查询集,您将在表单中获得0个选项。

它不能是动态的,因为在limit_choices_to中,您只能为UserProfile模型创建过滤器表达式。您无法访问该字段所属的Message实例,也无法访问该消息所属的Dialog模型...因此您无法创建过滤器来动态限制这些。

创建自己的ModelForm并限制那里的字段的查询集,在那里您可以获得所需的信息,这是正确的方法。

答案 1 :(得分:-1)

如果Message的实例都属于Dialog,为什么不在messages模型上创建字段Dialog?然后,您可以将发件人和收件人附加到每个Dialog。简而言之,这些方面的内容:

class Dialog(models.Model):
    messages = models.ManyToManyField(Message)
    sender = models.ForeignKey(UserProfile)
    receiver = models.ForeignKey(UserProfile)

class Message(models.Model):
    # Other fields

Message的发送者和接收者总是那些Dialog所属的那些。

相关问题