Django queryset that returns all unassigned fks
I have 2 models with a 1-1 relation (essentially a resource pool). For the example code, I will simply use nuts and bolts. There will be many more nuts (available resources) than bolts (which will each require 1 nut). However, if a nut can only be assigned to one bolt.
The constraint is easy enough to set up with the unique=True named param to the ForeignKey method.
The problem arises from the ModelForm. When rendered, the form will contain every nut in the dropdown. I would like to restrict it to only show nuts that haven't already been claimed by a bolt.
I am aware of the fields attribute of the ModelForm class, but am unable to come up with a query set filter that adequately addresses the issue. Here is example code of my problem:
from django.db import models
from django.forms import ModelForm
# Create 开发者_StackOverflowyour models here.
class Nut(models.Model):
size = models.CharField()
class Bolt(models.Model):
size = models.CharField()
nut = models.ForeignKey( Nut, unique=True )
class BoltForm(ModelForm):
def __init__(self, *args, **kwargs):
super(BoltForm, self).__init__(*args, **kwargs)
self.fields['nut'].queryset = # All unassigned nuts
Try this:
self.fields['nut'].queryset = Nut.objects.exclude(
pk__in=Bolt.objects.values('nut').query)
Update:
Of three expressions generating the same sql query:
pk__in=Bolt.objects.values('nut')
pk__in=Bolt.objects.values_list('nut')
pk__in=Bolt.objects.values('nut').query
I'd choose the last one as most straight-forward (although in other two cases the list and dict aren't created in fact: django 'understands' the intention without explicit mentioning of .query
)
Also, consider Daniel Roseman's answer. It is another approach to do the same thing.
Nut.objects.filter(bolt=None)
精彩评论