有没有办法在django内联formset clean方法中访问请求对象?

时间:2018-05-08 14:56:14

标签: django django-forms

使用内联和表单类获得此管理类:

class InvoiceAdmin(admin.ModelAdmin):
    ....
    inlines = [InvoiceLineInline, ]
    form = InvoiceForm
    ....

class InvoiceForm(forms.ModelForm):
    ....
    def clean():
        ....

    class Meta:
        model = Invoice
        exclude = []


class InvoiceLineInline(admin.TabularInline):
    model = InvoiceLine
    formset = InvoiceLineInlineFormset
    extra = 1


class InvoiceLineInlineFormset(forms.models.BaseInlineFormSet):
    def clean(self):
        super(InvoiceLineInlineFormset, self).clean()

        count = 0
        for form in self.forms:
            if not hasattr(form, 'cleaned_data'):
                continue

            data = form.cleaned_data
            try:
                if data:
                    count += 1
                else:
                    continue
            except AttributeError:
                pass

            if Decimal(data.get('quantity', 0)) <= 0:
                raise forms.ValidationError("Amount should be greater than 0.")
            ******************************************************
            _stock_code = data.get('stock_code', None)
            if not len(fetch_stocks_from_connector(request, stock_code=_stock_code)):
                raise forms.ValidationError("{} Stock code does not exist at connector.".format(_stock_code))
            ******************************************************    
        if count < 1:
            raise forms.ValidationError('Need one line at least.')

我需要使用外部方法对 InvoiceLineInlineFormset.clean 中每个 inlineform 中的_stock_code值进行额外验证,如上图所示。但是外部方法需要请求对象作为参数才能正常运行。

是否可以将请求对象传递给clean方法?

3 个答案:

答案 0 :(得分:1)

基础ModelAdmin类有_create_formsets()方法,它可以生成格式集:

def _create_formsets(self, request, obj, change):
    "Helper function to generate formsets for add/change_view."
    formsets = []
    inline_instances = []
    prefixes = {}
    get_formsets_args = [request]
    if change:
        get_formsets_args.append(obj)
    for FormSet, inline in self.get_formsets_with_inlines(*get_formsets_args):
        prefix = FormSet.get_default_prefix()
        prefixes[prefix] = prefixes.get(prefix, 0) + 1
        if prefixes[prefix] != 1 or not prefix:
            prefix = "%s-%s" % (prefix, prefixes[prefix])
        formset_params = {
            'instance': obj,
            'prefix': prefix,
            'queryset': inline.get_queryset(request),
        }
        if request.method == 'POST':
            formset_params.update({
                'data': request.POST,
                'files': request.FILES,
                'save_as_new': '_saveasnew' in request.POST
            })
        formsets.append(FormSet(**formset_params))
        inline_instances.append(inline)
    return formsets, inline_instances

正如您在formset_params课程中使用方法&#39; request参数扩展ModelAdmin所示,您可以在formset的课程中保存额外的kwarg请求{ {1}}以后通过__init__()clean()方法中使用它。

请注意,这不是最干净的解决方案,因为方法实现不允许轻松扩展kwargs,因此需要将整个方法移动到self.request和任何Django&#39;更新这部分代码,您需要相应地更新您的方法。

答案 1 :(得分:0)

我有几乎相同的问题(如何从内联方法获取request.user的内容),我得到了对我有用的答案: Django: access to user info from admin.py for methods with no request object?

答案 2 :(得分:0)

这个问题很旧,但我将分享对我有用的解决方案 ModelAdmin具有get_formset方法。您可以像这样扩展它

class YourAdminInline(admin.TabularInline):
    model = YourModel
    formset = YourInlineFormSet

    def get_formset(self,request,obj=None,**kwargs):
        formset = super(YourAdminInline,self).get_formset(request,obj,**kwargs)
        formset.request = request
        return formset

在表单集中,您可以使用self.request访问请求对象。例如在clean方法中

class YourInlineFormset(forms.BaseInlineFormset):
    def clean(self):
        ...
        request = self.request