将查询集传递给django inlineform中的foreignkeyfield

时间:2013-11-08 20:14:00

标签: python django django-forms django-queryset inline-formset

我遇到了一个小问题,我认为这个问题很常见。 这里描述的问题非常通用:

class Ownable(models.Model):
    user = models.ForeignKey(django.contrib.auth.models.User)

    class Meta:
        abstract = True


class Bowl(Ownable):
    pass


class Pea(Ownable):
    bowl = models.ForeignKey(bowl)

关系是:User [1:n] BowlUser [1:n] Pea Bowl [1:n] Pea

现在,当我想要创建新的Pea时,我还需要将其分配给Bowl,如下所示:

def create_new_pea(request):
    PeaFrom = inlineformset_factory(django.contrib.auth.models.User, Pea)
    return render(request, 'app/pea/create.html', {'formset': PeaFrom()})

我在这个过程中如何能够将QuerySet传递给bowl字段,因为用户只能将bean放入他自己的碗中。

我很高兴收到建议。我尝试为formset-factory创建自定义表单,但我需要request实例来了解当前用户。

2 个答案:

答案 0 :(得分:3)

一种简单的方法是在实例化formset后执行此操作。

def create_new_pea(request):
    PeaFormset = inlineformset_factory(django.contrib.auth.models.User, Pea)
    formset = PeaFormset(instance=request.user)
    for form in formset:
        form.fields['bowl'].queryset = request.user.bowl_set.all()
    return render(request, 'app/pea/create.html', {'formset': formset}

我认为可以将此行为构建到自定义Formset类中,从而覆盖_construct_forms方法:

class UserLimitedFormset(BaseInlineFormset):
    def _construct_forms(self):
        super(UserLimitedFormset, self)._construct_forms()
        for form in self:
            form.fields['bowl'].queryset = self.instance.bowl_set.all()

PeaFormset = inlineformset_factory(django.contrib.auth.models.User, Pea, formset=UserLimitedFormset)

要使用回调,我认为在创建formset之前,您需要一个闭包或functools.partial来记录用户。可能是这个,虽然它没有经过测试,我在封口上生锈了:

def create_new_pea(request):
    user = request.user
    def set_queryset(f, **kwargs):
        formfield = f.formfield(**kwargs)
        if f.name == 'bowl':
            formfield.queryset = user.bowl_set.all()
        return formfield
    PeaFormset = inlineformset_factory(django.contrib.auth.models.User, Pea, formfield_callback=set_queryset)

答案 1 :(得分:1)

不需要那么复杂 - 只需在表单初始化中添加一个kwarg'person'。我将这种新形式称为PeaForm,因为你列出的PeaForm实际上是Formset类型。

class PeaForm(ModelForm):

    def __init__(self, *args, **kwargs):

        person = kwargs.pop('person')
        super(PeaForm, self).__init__(*args, **kwargs)
        qs = Bowl.objects.filter(user=person)
        self.fields['bowl'].queryset = qs


    class Meta():
        model = Pea

当您在工厂中使用它时,您只需要在制作表单时讨论该方法:

from django.utils.functional import curry

person = request.user
PeaFormset = inlineformset_factory(django.contrib.auth.models.User, Pea, form=PeaForm)
PeaFormSet.form = staticmethod(curry(PeaForm, person=person))

现在只有属于用户的碗才会出现在PeaForm的QS中。