简体   繁体   中英

Django: validation of restricted Foreign keys forms in Mixins Class views

Context: how I handled foreign keys restrictions on GET

I have some trouble validating this form :

class RecordConsultationForm(forms.ModelForm):
    class Meta:
        model = Consultation
        fields = ["fk_type", "fk_client", "duration", "date"]

    def __init__(self, *args, **kwargs):
        self.user = kwargs.pop('user', None)
        super(RecordConsultationForm, self).__init__(*args, **kwargs)
        self.fields['fk_client'].queryset = Client.objects.filter(fk_owner=self.user) # <=====HERE

The queryset restricts the available clients to users . Pretty effective, I just had to add the following to get_context_data() :

@method_decorator(login_required, name='dispatch')
class BrowseConsultations(BrowseAndCreate):
    template_name = "console/browse_consultations.html"
    model = Consultation
    form_class = RecordConsultationForm
    success_url = 'browse_consultations'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['form'] = self.form_class(user = self.request.user)  #<=====HERE
        return context

    def post(self, request): 
        form = self.form_class(user = self.request.user) #<=====HERE
        return super().post(request)

Form validation on BrowseConsultations

Despite what I added in get_context_data() and post() , form data on POST does not seem valid, as if user were None (so it seems):

Invalid fk_client: Select a valid choice. 2 is not one of the available choices.

Maybe get_context_data() was not the proper place to set the user? Is there a way I could tweak the form in post() ? Is it the proper way to do it?

Additional details

BrowseAndCreate BrowseConsultations inherits from is a Mixing class I created to handle common ordering tasks and messages. Here is a portion of it:

@method_decorator(login_required, name='dispatch')
class BrowseAndCreate(CreateView, TemplateView):
    """display a bunch of items from a model and the form to create new instances"""

    def post(self, request):
        super().post(request)
        return redirect(self.success_url)

    def form_valid(self, form):
        super().form_valid(form)
        messages.add_message(self.request, messages.SUCCESS,
                             "Recorded in {}".format(self.object.status))

    def form_invalid(self, form):
        for e in form.errors.items():
            messages.add_message(self.request, messages.WARNING,
                                 "Invalid {}: {}".format(e[0], e[1][0]))

Environment

  • django 3.0.4
  • python 3.7

First of all, the CreateView (that your BrowseAndCreate inherits from) handles form validation in the post method, where it calls form_valid on success and form_invalid on failure. Both these methods should return an HTTP response.

Furthermore, the get_context_data from FormMixin that you are overriding already takes care of getting the form data.

If you need the user in your form, you could have this in your form:

class RecordConsultationForm(forms.Form):

    def __init__(self, user, *args, **kwargs):
        self.user = user
        super().__init__(*args, **kwargs)

And this in your view:

class BrowseConsultations(BrowseAndCreate):

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs['user'] = self.request.user
        return kwargs

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM