I have these models:
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')
What I want to do is limit the choices for the sender and receiver fields so that they can only be the users to which the whole dialog belongs. I tried this:
sender = models.ForeignKey(UserProfile,
related_name='sender',
limit_choices_to={'dialog':1})
which limits the choices but only for members of dialog with id=1. I'm wondering if this can be done dynamically?
I don't believe there is any way to dynamically filter like you want using limit_choices_to, as you won't have access to the needed objects to form such a query there.
Instead you should probably create your own model form for message and set the queryset for those fields there. Something like below...
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
Further, why limit_choices_to
works for your example, but is not dynamically useful.
Django simply processes the limit_choices_to
expression as an extra filter to be applied to the ModelForm fields queryset. Your expression {dialog: 1}
is semantically no different than if you were to assign the result of UserProfile.objects.filter(dialog=1)
to the queryset in my example.
Django does not know if a dialog with that id exists as a relation on the UserProfile, it just applies the filter. In this case a dialog with id 1 exists and so it works out. If you stick an invalid dialog id in your example instead..it would evaluate to an empty queryset and you would have get 0 choices in your form.
It cannot be dynamic because in limit_choices_to
you can only create a filter expression for the UserProfile model. You have no access to the Message instance the field belongs to, nor the Dialog model the message belongs to...hence you cannot create a filter to dynamically limit to those.
Creating your own ModelForm and limiting the queryset for the field there, where you have the information you need, is the proper way to do it.
If instances of Message
all belong to a Dialog
, why not create a field messages
on the Dialog
model? Then, you could attach a sender and receiver to each Dialog
. In short, something along these lines:
class Dialog(models.Model):
messages = models.ManyToManyField(Message)
sender = models.ForeignKey(UserProfile)
receiver = models.ForeignKey(UserProfile)
class Message(models.Model):
# Other fields
Sender and receiver of the Message are then always those to which the Dialog belongs.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.