我想只列出OneToOneField中的可用项目而不是所有项目,它不像ChoiceField中的过滤值那样,因为我们只需找出可以使用的值,这些值基于是否已经使用过的原则
我的模型定义如下:
class Foo(models.Model):
somefield = models.CharField(max_length=12)
class Bar(models.Model):
somefield = models.CharField(max_length=12)
foo = models.OneToOneField(Foo)
现在我使用ModelForm基于Bar模型创建表单:
class BarForm(ModelForm):
class Meta:
model = Bar
现在问题在于它使用HTML的select小部件显示ChoiceField中数据库中可用的所有Foo对象的列表,因为该字段是OneToOneField,django将强制将Bar对象单个关联到Foo对象,但是因为它显示列表中所有可用和不可用的项目,所以很难找出表格中可接受的值,并且用户被迫使用命中/试用方法找出正确的选项。
如何更改此行为并仅列出可以使用的字段中的项目?
答案 0 :(得分:3)
虽然这是一个老话题,但我遇到了它寻找相同的答案。
调整BarForm,使其看起来像:
class BarForm(ModelForm):
class Meta:
model = Bar
def __init__(self, *args, **kwargs):
super(BarForm, self).__init__(*args, **kwargs)
#only provide Foos that are not already linked to a Bar, plus the Foo that was already chosen for this Bar
self.fields['foo'].queryset = Foo.objects.filter(Q(bar__isnull=True)|Q(bar=self.instance))
这应该可以解决问题。你覆盖init函数,这样你就可以编辑表单中的foo字段,为它提供一个更具体的可用Foo查询集,并且(相当重要)已经选择的Foo。
我原来的问题是:如何仅显示OneToOne关系中的可用用户?
我的models.py
中的Actor模型如下所示:
class Actor(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name = 'peactor')
# lots of other fields and some methods here
在我的admin.py
我有以下课程:
class ActorAdmin(admin.ModelAdmin):
# some defines for list_display, actions etc here
form = ActorForm
之前我没有使用过特殊的表单(只是依赖于Django默认为ModelAdmin提供的基本ModelForm)但我需要它来解决问题。
所以,最后,在我的forms.py
我有:
class ActorForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(ActorForm, self).__init__(*args, **kwargs)
#only provide users that are not already linked to an actor, plus the user that was already chosen for this Actor
self.fields['user'].queryset = User.objects.filter(Q(peactor__isnull=True)|Q(peactor=self.instance))
所以我在这里创建一个ActorForm并覆盖__init__
方法。
self.fields['user'].queryset =
设置用户表单域使用的查询集。此表单域是ModelChoiceField 默认情况下,模型上的OneToOneField(或ForeignKey)。
Q(peactor__isnull=True)|Q(peactor=self.instance)
Q代表Q-objects帮助"复杂"查询类似于or
语句。
所以这个查询说:没有设置peactor,或者peactor与为这个actor选择的peactor相同
peactor
是演员的related_name
。
这样,您只会获得可用的用户以及不可用的用户,因为它已链接到您当前正在编辑的对象。
我希望这可以帮助有同样问题的人。 : - )
答案 1 :(得分:1)
您需要在表单的 init ()方法中使用此类内容。
def __init__(self, *args, **kwargs):
super(BarForm, self).__init__(*args, **kwargs)
# returns Bar(s) who are not in Foo(s).
self.fields['foo'].queryset = Bar.objects.exclude(id__in=Foo.objects.all().values_list(
'bar_id', flat=True))
PS:代码未经过测试。