仅在OneToOneField Django

时间:2015-10-12 10:19:51

标签: django django-models django-forms

我想只列出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对象,但是因为它显示列表中所有可用和不可用的项目,所以很难找出表格中可接受的值,并且用户被迫使用命中/试用方法找出正确的选项。

如何更改此行为并仅列出可以使用的字段中的项目?

2 个答案:

答案 0 :(得分:3)

虽然这是一个老话题,但我遇到了它寻找相同的答案。

特别针对OP:

调整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:代码未经过测试。