Envoi d'objet request.user à ModelForm de vue générique basée en classe Django
-
24-10-2019 - |
Question
Alors, mon objectif est d'être en mesure de filtrer un dans mon ModelForm pour inclure uniquement les queryset ModelChoiceField lieux qui request.user a créé.
Mon ModelForm est simplement:
class PlaceEventForm(models.ModelForm):
class Meta:
model = Event
Je voudrais pouvoir ajouter quelque chose comme:
def __init__(self, *args, **kwargs):
super(PlaceEventForm, self).__init__(*args, **kwargs)
self.fields['place'].queryset = Place.objects.filter(created_by=request.user)
Cependant, je ne peux pas sembler trouver un moyen d'accéder à la demande dans le ModelForm.
Selon moi, comme ceci:
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)
Je ne sais pas si cela est encore à ce que je dois faire, mais j'essayé:
def get_form_kwargs(self):
kwargs = super(PlaceEventFormView, self).get_form_kwargs()
kwargs.update({'place_user': self.request.user})
return kwargs
Mais je suis l'erreur: init () a obtenu un argument inattendu mot-clé 'place_user'
Toutes les idées sur celui-ci? Ou peut-on penser à un moyen de filtrer mon ModelChoiceField dans la vue, sans avoir besoin de passer ma demande à la ModelForm?
La solution
Vous devez pop user
clé kwargs
dans la méthode de PlaceEventForm.__init__()
, pour l'empêcher d'aller à la méthode de 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)
Autres conseils
Je suis sur un iPhone, mais faire ceci:
def get_form(self, form_class):
form = super(MyView, self).get_form(form_class)
form.fields['place'].querset = Place....
return form
Wow qui était dur! Pas de support indention!
Pour mettre à jour la réponse de Yuji pour Django 1.10+ (y compris Django 2.0+), voir l'exemple ci-dessous (notez la signature de la méthode mise à jour). L'approche proposée par Yuji maintient le queryset dans la vue ainsi que l'autre logique métier, et aide à garder une classe de forme models.ModelForm
extension propre et simple.
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
Shorter:
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