Администратор django - доступ к request.user в BaseInlineFormSet - PullRequest
3 голосов
/ 14 декабря 2011

Я только что создал forms.models.BaseInlineFormSet, чтобы переопределить набор форм по умолчанию для модели TabularInline. Мне нужно оценить группу пользователей в проверке набора форм (clean), потому что некоторые группы должны написать число в диапазоне (0,20).

Я использую администратор django для автоматического создания интерфейса.

Я пытался получить запрос и пользователя от kwargs в методе init , но не смог получить ссылку.

Вот что у меня сейчас:

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

Затем я использую его как inlines = [OrderItemInline,] в моем ModelAdmin.

К сожалению, self.user всегда None, поэтому я не могу сравнить группу пользователей, и фильтр не применяется. Мне нужно отфильтровать его, потому что другие группы должны иметь возможность указать любой процент скидки.

Как я могу это сделать? Если вам также нужен код ModelAdmin, я опубликую его (я просто избежал копирования всего кода, чтобы избежать путаницы).

1 Ответ

7 голосов
/ 14 декабря 2011

Хорошо, я узнаю свой код в вашем вопросе, поэтому, я думаю, мне лучше попробовать и ответить на него. Но я бы сказал прежде всего, что этот фрагмент действительно предназначен только для проверки минимального количества форм в наборе форм. Ваш вариант использования отличается - вы хотите что-то проверить в каждой форме. Это должно быть сделано с проверкой на уровне формы, а не формы.

Тем не менее, проблема не в самом коде, который вы разместили, а в том, что это только его часть. Очевидно, что если вы хотите получить пользователя из 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)
...