Reputation: 83
Lets say I have two models and a form:
class Person(models.Model):
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
class Car(models.Model):
plate = models.CharField(max_length=255)
persons = models.ManyToManyField(Person)
class CarAddForm(forms.ModelForm):
plate = forms.CharField()
persons = forms.ModelMultipleChoiceField(queryset=Person.objects.all())
class Meta:
model = Car
fields = [
'plate',
'persons'
]
Is there a way to get ModelMultipleChoiceField queryset of people that are NOT associated with any car? In case of editing Car model object, the queryset should contain people that are NOT associated with any car PLUS people that are associated with the car being edited
PS: maybe there is a better way to achieve this?
Upvotes: 3
Views: 1430
Reputation: 88569
You can make use of the limit_choices_to
--(Doc) argument of ManyToManyField
as
class Car(models.Model):
plate = models.CharField(max_length=255)
persons = models.ManyToManyField(
Person,
limit_choices_to={"car__isnull": True}
)
Alternatively, you can also alter the queryset
argument of ModelMultipleChoiceField
as
class CarAddForm(forms.ModelForm):
plate = forms.CharField()
persons = forms.ModelMultipleChoiceField(
queryset=Person.objects.filter(car__isnull=True)
)
class Meta:
model = Car
fields = [
'plate',
'persons'
]
Upvotes: 1
Reputation: 16505
You can specify a filter for the query:
from django.db import models
class CarAddForm(forms.ModelForm):
...
persons = forms.ModelMultipleChoiceField(
queryset=Person.objects\
.annotate(car_count=models.Count('cars'))\
.filter(car_count=0))
...
Another options is to override the forms __init__()
method. Maybe like this:
from django.db import models
class CarAddForm(forms.ModelForm):
...
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['person'].queryset = self.fields['person'].queryset\
.annotate(car_count=models.Count('cars'))\
.filter(car_count=0))
Upvotes: 1