2011-04-27 1 views
12

Итак, моя цель - уметь фильтровать запрос на выбор ModelChoiceField в моей модели ModelForm, чтобы включить только те места, которые создали request.user.Отправка объекта request.user в ModelForm из общего представления класса в Django

Мои ModelForm просто:

class PlaceEventForm(models.ModelForm): 
    class Meta: 
     model = Event 

Я хотел бы иметь возможность добавить что-то вроде:

def __init__(self, *args, **kwargs): 
    super(PlaceEventForm, self).__init__(*args, **kwargs) 
    self.fields['place'].queryset = Place.objects.filter(created_by=request.user) 

Однако, я не могу найти способ доступа запрос в ModelForm.

мой взгляд, как так:

class PlaceEventFormView(CreateView): 
    form_class = PlaceEventForm 
    template_name = 'events/event_create.html' 

    @method_decorator(login_required) 
    def dispatch(self, *args, **kwargs): 
     return super(PlaceEventFormView, self).dispatch(*args, **kwargs) 

Я не уверен, если это даже близко к тому, что я должен делать, но я пытался:

def get_form_kwargs(self): 
    kwargs = super(PlaceEventFormView, self).get_form_kwargs() 
    kwargs.update({'place_user': self.request.user}) 
    return kwargs 

Но я получил ошибку: init() получил неожиданное ключевое слово аргумент 'place_user'

Любые идеи по этому вопросу? Или кто-нибудь может подумать о способе фильтрации моего ModelChoiceField в представлении без необходимости передавать мой запрос в ModelForm?

ответ

20

Вы должны совать ключ user из kwargs в PlaceEventForm.__init__() методе, чтобы предотвратить его от идти к ModelForm.__init__() метода:

views.py:

class PlaceEventFormView(CreateView): 
    form_class = PlaceEventForm 
    template_name = 'events/event_create.html' 

    @method_decorator(login_required) 
    def dispatch(self, *args, **kwargs): 
     return super(PlaceEventFormView, self).dispatch(*args, **kwargs) 

    def get_form_kwargs(self): 
     kwargs = super(PlaceEventFormView, self).get_form_kwargs() 
     kwargs.update({'place_user': self.request.user}) 
     return kwargs 

forms.py:

class PlaceEventForm(models.ModelForm): 
    class Meta: 
     model = Event 

    def __init__(self, *args, **kwargs): 
     user = kwargs.pop('place_user') 
     # now kwargs doesn't contain 'place_user', so we can safely pass it to the base class method 
     super(PlaceEventForm, self).__init__(*args, **kwargs) 
     self.fields['place'].queryset = Place.objects.filter(created_by=user) 
+0

Большое спасибо! Работает отлично. – Brian

+0

Проблемы с пониманием того, как вы это делаете. –

+0

Я сделал пример завершенным, дайте мне знать, если он все еще неясен –

1

Я нахожусь на iPhone, но сделаю так:

def get_form(self, form_class): 
    form = super(MyView, self).get_form(form_class) 
    form.fields['place'].querset = Place.... 
    return form 

Ничего себе, это было сложно! Нет поддержки отступничества!

0

Чтобы обновить ответ Yuji для Django 1.10+ (включая Django 2.0+), см. Пример ниже (обратите внимание на обновленную подпись метода). Предлагаемый подход Юдзи держит запрос в представлении вместе с другой бизнес-логикой и помогает поддерживать класс формы, отличный от нуля, и чистым и понятным.

def get_form(self, form_class=None): 
    if form_class is None: 
     form_class = self.get_form_class() 
    form = super(MyView, self).get_form() 
    form.fields['place'].queryset = Place.objects.filter(created_by=self.request.user) 
    return form 

Шортер:

def get_form(self, form_class=None): 
    form = super(MyView, self).get_form(form_class) 
    form.fields['place'].queryset = Place.objects.filter(created_by=self.request.user) 
    return form 
Смежные вопросы