Django form field after POST request

I am using class-based views (FormView) and I would like to save the search keyword after submitting the form (POST request). I tried this in the form_valid method:

 def form_valid(self, form): self.initial['search'] = form.data['search'] ... 

but it will show it to all users. This is a fairly common solution for many forms of web search (not to mention Google search), so I wonder how this can be done in Django.

Update: Mon Jun 19 13:18:42 UTC 2017

Based on some answers below, I will have to rephrase my question.

I have a simple form with several input fields, after submitting the form, it will request other sites to get results based on a search query. I would like to save some results in the database, mainly for creating statistics, redisplaying the form with the selected fields and displaying the results.

Currently, data is stored on the class object and passed from POST to GET. This is not a good solution for obvious security reasons:

 class SearchView(FormView): ... data = dict() def form_valid(self, form): .... self.data['results'] = results def get_context_data(self, **kwargs): context = super(IndexView, self).get_context_data(**kwargs) context['data'] = self.data.pop('results', None) return context 

Question:

What would be the best way to display the form (with the selected fields) and the results on the same page, preferably without sessions or storing them in a database between POST and GET.

Points that I have already reviewed:

  • Do not redirect the user (visualize the template with the current context immediately, while we still have the response object). I don't like the fact that the page refresh will resubmit the form.

  • Save the answer in some key value storage, for example Redis, and redirect the user to something like the results / {result_id}, where we can get a response from the database to pre-fill the form with data and show the results - this sounds reasonable, but I will need to add another component to pass the POST results to GET.

  • Use GET for this type of form - I realized that we must use POST to modify the data

+6
source share
7 answers

Google and other similar searches use GET parameters to pass a query string.

An example :

  1. Google test
  2. The URL of the result will be https://www.google.ru/?q=test

So basically you need to use the same approach and pass the search string as a GET param.

Here is a general idea

 class SearchView(View): success_url = reverse('result-view') def get_success_url(self): success_url = super().get_success_url() return '{0}?search={1}'.format(success_url, self.form.cleaned_data['search']) ... class ResultView(View): def get(self, request, *args, **kwargs): search_string = request.GET.get('search', '') 
+4
source

You did not specify how long you want to keep the keyword.

If this is exactly the answer, while you are showing the form correctly, the keyword will still be:

 >>> from django import forms >>> class MyForm(forms.Form): ... search = forms.CharField() ... >>> f = MyForm(data={'search': 'KEYWORD'}) >>> print(f['search']) <input id="id_search" name="search" type="text" value="KEYWORD" /> 

If you want to save the keyword for all queries, but only for this user, use the session framework :

 def form_valid(self, form): self.request.session['search'] = form.data['search'] ... def get_form(self, form_class): form = super(self, YourView).get_form(form_class) form.initial['search'] = self.request.session.get('search', '') return form 
+2
source

views.py

 class SearchView(FormView): template_name = 'apps/frontend/search_view.j2' def get_form_class(self): class _Form(forms.Form): search = forms.CharField(label='search') return _Form def form_valid(self, form): return self.render_to_response(self.get_context_data(form=form)) 

HTML

 <h1>current:{{ form.search.value()|default('') }} - jinja2 format</h1> <form action="." method="post"> {% csrf_token %} {{ form }} <button type="submit">submit</button> </form> 
+2
source

From your update: I think this is the process you are looking for:

  • User fills out a form with an empty search term
  • user POST search query form
  • you request other sites in this POST request and show your form again using the term
  • the user is provided with a pre-filled form and results (without redirecting or you lose context).

Basically you need to prevent redirection when the form is valid:

 class SearchPageView(FormView): def form_valid(self, form): # do your things (3) here context = self.get_context_data(form=form) context['results'] = ['lorem', 'ipsum'] return self.render_to_response(context) 
+2
source

Here's an implementation that, I believe, satisfies all your requirements. In particular, we can submit a user request using form_valid() return super(SearchView, self).get(self.request) . Thus, the Django server behaves like processing a regular POST operation from the user's point of view.

views.py

 class SearchView(FormView): template_name = 'yourapp/search.html' form_class = SearchForm results = '' # for {{ view.results }} def form_valid(self, form): self.results = form.get_results() return super(SearchView, self).get(self.request) 

forms.py

 class SearchForm(forms.Form): input = forms.CharField() def get_results(self): input_data = self.cleaned_data['input'] results = "results for %s" % input_data # <-- modify this process as you need # ... (your operations for input_data and results here) return results 

YourApp / search.html

 <form action="" method="post">{% csrf_token %} {{ form.as_p }} <input type="submit" value="Search" /> </form> <p>{{ view.results }}</p> 
+2
source

Use GET for this type of form - I realized that we must use POST to modify the data

Use GET only to fill in the values ​​of form.initial , you can submit the form as POST.

 # for python3 # from urllib.parse import urlencode from urllib import urlencode class SearchView(FormView): def get_initial(self): return {'search': self.request.GET.get('search')} def form_valid(self, form): search = self.request.POST.get('search') url = self.get_success_url() + '?' + urlencode({'search': search}) return HttpResponseRedirect(url) 
+2
source

I'm still a little sure what you want to do (searches are usually done via GET, and then Django shows the desired behavior). But I think you should do this by overwriting get_initial(): and pulling the values ​​from self.request.POST .

If all you want to do is save the presented value when initializing the next value, this is the best approach.

those. something like this inside the View class for Python 3 (your super call should be a little different in Python 2):

 def get_initial(self): initial = super().get_initial() initial['search'] = self.request.POST.get('search', '') return initial 
+1
source

Source: https://habr.com/ru/post/1268820/


All Articles