【问题标题】:Is there a way to access request object in django inline formset clean method?有没有办法在 django inline formset clean 方法中访问请求对象?
【发布时间】:2018-10-18 13:57:12
【问题描述】:

得到这个带有内联和表单类的管理类:

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 方法?

【问题讨论】:

  • 可能是kwargs['instance'] 你在找什么?在自定义管理表单中我使用它。

标签: django django-forms


【解决方案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

正如您所看到的,通过在 ModelAdmin 类中使用方法的 request 参数扩展 formset_params,您可以在表单集的类 __init__() 中使用请求保存额外的 kwarg,然后通过 @987654329 在 clean() 方法中使用它@。

请注意,这不是最干净的解决方案,因为方法实现不允许仅轻松扩展 kwargs,因此需要将整个方法移至您的 ModelAdmin 并使用 Django 对这部分的任何更新您需要相应地更新您的方法的代码。

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      这个问题很老,但我会分享对我有用的解决方案 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
      

      【讨论】:

        猜你喜欢
        • 2012-03-28
        • 2016-03-31
        • 2018-11-08
        • 1970-01-01
        • 1970-01-01
        • 2021-08-11
        • 2018-04-05
        • 2017-12-08
        • 2012-03-01
        相关资源
        最近更新 更多