2

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

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] Bowl, User [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()})

在这个过程中,我如何能够将 a 传递QuerySetbowl-field,因为用户只能将 bean 放入自己的碗中。

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

4

2 回答 2

3

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

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)

要使用回调,我认为您需要一个闭包或 afunctools.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)
于 2013-11-08T21:16:09.377 回答
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

当您在工厂中使用它时,您只需在制作表单时对方法进行 curry:

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 中。

于 2013-11-08T23:38:56.303 回答