【问题标题】:django admin - access request.user in BaseInlineFormSetdjango admin - 访问 BaseInlineFormSet 中的 request.user
【发布时间】:2012-01-20 06:56:25
【问题描述】:

我刚刚创建了一个forms.models.BaseInlineFormSet 来覆盖 TabularInline 模型的默认表单集。我需要在表单集验证 (clean) 中评估用户组,因为某些组必须在范围 (0,20) 内写入数字。

我正在使用 django admin 来自动生成界面。

我尝试在 init 方法中从 kwargs 获取请求和用户,但我无法获得参考。

这就是我现在拥有的:

class OrderInlineFormset(forms.models.BaseInlineFormSet):
    def __init__(self, *args, **kwargs):
        self.user = kwargs.pop('user')
        super(OrderInlineFormset, self).__init__(*args, **kwargs)

    def clean(self):
        # get forms that actually have valid data
        count = 0
        for form in self.forms:
            try:
                if form.cleaned_data:
                    count += 1
                    if self.user.groups.filter(name='Seller').count() == 1:
                        if form.cleaned_data['discount'] > 20:
                            raise forms.ValidationError('Not authorized to specify a discount greater than 20%')
            except AttributeError:
                # annoyingly, if a subform is invalid Django explicity raises
                # an AttributeError for cleaned_data
                pass
        if count < 1:
            raise forms.ValidationError('You need to specify at least one item')

class OrderItemInline(admin.TabularInline):
    model = OrderItem
    formset = OrderInlineFormset

然后我在我的 ModelAdmin 中将其用作 inlines = [OrderItemInline,]

不幸的是 self.user 总是None 所以我无法比较用户组并且没有应用过滤器。我需要过滤它,因为其他组应该能够指定任何折扣百分比。

我该怎么办?如果您还需要 ModelAdmin 代码,我会发布它(我只是避免复制整个代码以避免混淆)。

【问题讨论】:

    标签: django django-models django-admin django-forms


    【解决方案1】:

    嗯,我在你的问题中认出了我的代码,所以我想我最好试着回答一下。但我首先要说的是,sn-p 实际上只是用于验证表单集中的最小数量的表单。你的用例是不同的——你想在每个表单中检查一些东西。这应该通过表单级别的验证来完成,而不是表单集。

    也就是说,问题实际上并不在于您发布的代码,而在于这只是其中的一部分。显然,如果您想在初始化表单或表单集时从 kwargs 中获取用户,您需要确保用户实际上被传递到该初始化中 - 默认情况下不是这样。

    不幸的是,Django 的管理员并没有真正给你一个适当的钩子来拦截初始化本身。但是您可以通过覆盖get_form 函数并使用functools.partial 将表单类与请求参数包装起来作弊(此代码未经测试,但应该可以工作):

    from functools import partial
    
    class OrderForm(forms.ModelForm):
        def __init__(self, *args, **kwargs):
            self.user = kwargs.pop('user')
            super(OrderForm, self).__init__(*args, **kwargs)
    
        def clean(self)
             if self.user.groups.filter(name='Seller').count() == 1:
                 if self.cleaned_data['discount'] > 20:
                     raise forms.ValidationError('Not authorized to specify a discount greater than 20%')
             return self.cleaned_data
    
    class MyAdmin(admin.ModelAdmin):
        form = OrderForm
    
        def get_form(self, request, obj=None, **kwargs):
            form_class = super(MyAdmin, self).get_form(request, obj, **kwargs)
            return functools.partial(form_class, user=request.user)
    

    【讨论】:

    • 抱歉挖掘了这么旧的帖子,但我偶然发现了这个解决方案,在实施时我得到:'functools.partial' object has no attribute 'base_fields'
    【解决方案2】:

    这是另一个不使用部分的选项。首先覆盖TabularInline 类中的get_formset 方法。

    分配request.user 或您需要在表单集中提供的任何额外变量,如下例所示:

    class OrderItemInline(admin.TabularInline):
        model = OrderItem
        formset = OrderInlineFormset
    
        def get_formset(self, request, obj=None, **kwargs):  
           formset = super(OrderProductsInline, self).get_formset(request, obj, **kwargs)
           formset.user = request.user
           return formset
    

    现在用户在表单集中可用self.user

    class OrderInlineFormset(forms.models.BaseInlineFormSet):
    
        def clean(self):
          print(self.user) # is available here 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-07-20
      • 1970-01-01
      • 2011-10-04
      • 2012-08-19
      • 1970-01-01
      • 1970-01-01
      • 2012-04-28
      相关资源
      最近更新 更多