简体   繁体   中英

Get objects that are not in manytomany relationship of a different model?

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?

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,
        
    )

Alternatively, you can also alter the queryset argument of ModelMultipleChoiceField as

class CarAddForm(forms.ModelForm):
    plate = forms.CharField()
    persons = forms.ModelMultipleChoiceField(
        
    )

    class Meta:
        model = Car
        fields = [
            'plate',
            'persons'
        ]

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))

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM