【问题标题】:Pass request to inline form in Django Admin?在 Django Admin 中将请求传递给内联表单?
【发布时间】:2016-08-20 04:48:25
【问题描述】:

我正在尝试从 Django Admin 中的请求中获取用户。我需要的是在内联表单的clean() 方法中访问请求的用户。我已经使用普通的ModelForm(即不是内联的)完成了类似于下面描述的过程,并且我成功了。但是,使用内联我遇到了很多问题。 我有:

class SaleFormset(BaseInlineFormSet):
    def __init__(self, *args, **kwargs):
        self.request = kwargs.pop('request')
        super(SaleFormset, self).__init__(*args, **kwargs)

    def _construct_form(self, i, **kwargs):
        kwargs['request'] = self.request
        super(SaleFormset, self)._construct_form(i, **kwargs)


class SaleProductItemInlineForm(ModelForm):
    """
    Custom form for the Sale Product Item Inline used by the
    Sale Admin form.
    """

    def __init__(self, *args, **kwargs):
        self.request = kwargs.pop('request')
        super(SaleProductItemInlineForm, self).__init__(*args, **kwargs)

    class Meta:
        model = SaleProductItem
        fields = "__all__"  

在 admin.py 中,我有:

class SaleProductItemInline(admin.TabularInline):
    """
    Tabular inline for a SaleProductItem used in the Sale Admin.
    """
    model = models.SaleProductItem
    form = SaleProductItemInlineForm
    formset = SaleFormset

    def get_formset(self, request, obj=None, **kwargs):
        formset_class = super(SaleProductItemInline, self).get_formset(request, obj, **kwargs)

        class Subset(formset_class):
            def __new__(cls, *args, **kwargs):
                kwargs['request'] = request
                return formset_class(*args, **kwargs)

        return Subset

但是,由于此部分,我收到一条错误消息,提示 'NoneType' object has no attribute 'media'

@property
def media(self):
    # All the forms on a FormSet are the same, so you only need to
    # interrogate the first form for media.
    if self.forms:
        return self.forms[0].media

【问题讨论】:

    标签: django forms admin


    【解决方案1】:

    类似的方法对我有用:

    def SaleProductItemInlineFormFactory(request):
        class SaleProductItemInlineForm(ModelForm):
            def __init__(self, *args, **kwargs):
                # here finally you can do something with your request
                super(SaleProductItemInlineForm, self).__init__(*args, **kwargs)
    
            class Meta:
                model = SaleProductItem
                fields = "__all__"
        return SaleProductItemInlineForm
    
    def SaleProductItemInlineFactory(request):
        class SaleProductItemInline(admin.TabularInline):
            model = models.SaleProductItem
            form = SaleProductItemInlineFormFactory(request)
    
        return SaleProductItemInline
    
    class SaleAdmin(admin.ModelAdmin):
        inlines = ()
    
        # such way we send request to main form
        def get_form(self, request, obj=None, **kwargs):
            form = super(SaleAdmin, self).get_form(request, obj=obj, **kwargs)
            form.request = request
            return form
    
        # we define inlines with factory to create Inline class with request inside
        def change_view(self, request, object_id, form_url='', extra_context=None):
            self.inlines = (SaleProductItemInlineFactory(request), )
            return super(SaleAdmin, self).change_view(request, object_id)
    
        # we define inlines with factory to create Inline class with request inside
        def add_view(self, request, form_url='', extra_context=None):
            self.inlines = (SaleProductItemInlineFactory(request), )
            return super(SaleAdmin, self).add_view(request)
    

    【讨论】:

    • add_view() 的哪个位置可以访问object_id 以传递给change_view()
    • 当然add_view() 应该调用add_view()。我修好了它。谢谢
    • 无法想象为了达到这个目的而进行如此讨厌和复杂的工作......
    【解决方案2】:

    您的解决方案的捷径是:

    class SaleFormset(BaseInlineFormSet):
    
        def _construct_form(self, i, **kwargs):
            form = super(SaleFormset, self)._construct_form(i, **kwargs)
            form.request = self.request
            return form
    
    class SaleProductItemInline(admin.TabularInline):
        model = models.SaleProductItem
        form = SaleProductItemInlineForm
        formset = SaleFormset
    
        def get_formset(self, request, obj=None, **kwargs):
            formset = super(SaleProductItemInline, self).get_formset(request, obj, **kwargs)
            formset.request = request
            return formset
    

    【讨论】:

    • _construct_form 是公共 API 的一部分吗?
    • 使用partialmethod 的更短且线程安全的替代方案:formset._construct_form = partialmethod(formset._construct_form, user=request.user)。无需派生BaseInlineFormSet
    猜你喜欢
    • 2015-08-27
    • 2014-03-19
    • 1970-01-01
    • 2011-11-10
    • 2012-05-17
    • 1970-01-01
    • 2012-11-27
    • 1970-01-01
    • 2011-07-11
    相关资源
    最近更新 更多