Passing data from post form to FileResponde view - python

I recently started using Django and I managed to create two views, one to submit a form and another to return a FileResponse, separately, they work fine.
Now, I need to integrate both, when the client submit the form, I want to redirect to the another view using the fields submitted at the previous form. How can I do that?
Here is my form view:
def submitForm(request):
if 'report' in request.POST:
date_start = request.POST.get('date_start')
date_end = request.POST.get('date_end')
state = request.POST.get('state')
return render(request, 'comissao.html')
Here is my view that creates a pdf file
def createPdf(request):
date_start = '20220301'
date_end = '20220331'
state = 'G00471'
body = "some html"
options = { 'quiet': '' }
pdfkit.from_string(body, options=options)
file = open('file.pdf', 'rb')
return FileResponse(file)
As you can see, I need the information passed at my first view, to use at second view, I tried something like this, but I think I'm mistaking the concept,
return reverse('pdf', kwargs={'state':state, 'date_start':date_start, 'date_end':date_end})

reverse() only returns the URL, but I think you rather want to do a redirect() to that view.
For passing the parameters you have several options:
GET parameters
Session
URL parameters
Let's use GET parameters, which I would suggest:
from urllib.parse import urlencode
...
def submitForm(request):
...
response = redirect('pdf')
params = { state' : state, 'date_start: date_start, 'date_end': date_end}
response['Location'] += f'?{urlencode(params)}'
return response
Then in your PDF view you need to parse the GET parameters:
def createPdf(request):
date_start = request.GET.get("date_start")
...
Note that you may also need to convert your dates into string and back for the query, which I ignored here.

Related

Dynamic consuming of web API in Django based on user's choice

The program I am trying to write requires that whenever the user changes a value in a form on Django website, that value will be written to the variable and then inserted into the API's url as parameter inside requests.get() function in views.py file.
So basically my Django website is to consume web API.
API returns different data sets ​​depending on the explicit endpoint. It can change dynamically depending on what the user chooses in a form, and then, if submit button is clicked, show the content on a django website immediately.
Here is the Web API which I use to get data sets:
http://api.nbp.pl/en.html
forms.py:
from django import forms
class DateInput(forms.DateInput):
input_type = 'date'
class ExampleForm(forms.Form):
my_date_field = forms.DateField(widget = DateInput)
views.py:
from django.shortcuts import render
import requests
from .forms import ExampleForm
def home(request):
submitbutton = request.POST.get("submit") # I check if submit button is clicked
form = ExampleForm()
date2 = ''
if form.is_valid():
date2 = form.cleaned_data.get("my_date_field") # write date choosen by user to variable
# And now I have a problem. I want to use the value of this variable to specify an endpoint:
response = requests.get(f"http://api.nbp.pl/api/exchangerates/tables/a/2012-01-01/{date2}/")
Api = response.json()
context= {'form': form, 'submitbutton': submitbutton, "Api": Api}
return render(request, 'home.html', context)
The user selects a date in the form and based on that date, the data set is returned.
I have no problem with the HTML template file. I know how to insert form and submit button on a website, and how to view the data set using API, but my goal is to make it flexible - dependent on form value.
Current code returns error: JSONDecodeError. The help would be greatly appreciated.
Yes, URL constructed using the f-string returns data.
I found that if I don't use the function is_valid(), form is invalid but code returns correct reponse (Response [200]) and as a result the data is correctly displayed without error, but this only happens if the value of date2 is constant - this is not what interests me, I want it to be taken from the form!
Please have someone look at my code and say if I am doing something wrong, I am tired of this problem...
from django.shortcuts import render
import requests
from .forms import ExampleForm
def home(request):
submitbutton = request.POST.get("submit")
date2 = '2020-01-17'
if request.method == 'POST':
form = ExampleForm(request.POST)
if form.is_valid():
print("Is Valid")
date2 = form.cleaned_data.get("my_date_field")
date_string = str(date2)
argument = f"http://api.nbp.pl/api/exchangerates/tables/a/2012-01-01/{date_string}/"
response = requests.get(argument)
Api = response.json() # This causes an error, because response is incorrect, I don't know why
return render(request, 'home.html', {'form': form, 'submitbutton': submitbutton, "Api": Api} )
else:
print("Is no valid")
form = ExampleForm()
date2 = '2012-01-10'
response = requests.get(f"http://api.nbp.pl/api/exchangerates/tables/a/2012-01-01/{date2}/")
Api = response.json() # This doesn't cause an error, response is correct - but that way value of variable is not taken from the form...
context= {'form': form, 'submitbutton': submitbutton, "Api": Api}
return render(request, 'home.html', context)

Pass Django variables between view functions

I'm asking a question about variables handling in my Django application view.
I have 2 functions :
The first one lets me to display query result in an array with GET filter parameter (in my case, user writes year and Django returns all objects according to this year. We will call query_naissance this variable).
The second one lets me to create a PDF. I have lots of variables but I want to take one more time query_naissance in my PDF.
This is my first function :
#login_required
def Table_annuelle_BirthCertificate(request) :
query_naissance = request.GET.get('q1')
...
return render(request, 'annuel.html', context)
And my second function looks like :
#login_required
def Table_Naissance_PDF(request) :
data = {"BirthCertificate" : BirthCertificate}
template = get_template('Table_raw.html')
html = template.render(Context(data))
filename = str('Table annuelle Naissance.pdf')
path = '/Users/valentinjungbluth/Desktop/Django/Individus/' + filename
file = open(path, "w+b")
pisaStatus = pisa.CreatePDF(html.encode('utf-8'), dest=file, encoding='utf-8')
file.close()
context = {
"BirthCertificate":BirthCertificate,
"query_naissance":query_naissance,
}
return render(request, 'Table.html', context) # Template page générée après PDF
So How I can add query_naissance given by user in my first function to my second one without write one more time a field ?
Then, I have to call this variable like {{ query_naissance }} in my HTML template.
Thank you
In order to persist information across requests, you would use sessions. Django has very good session support:
# view1: store value
request.session['query_naissance'] = query_naissance
# view2: retrieve vlaue
query_naissance = request.session['query_naissance']
# or more robust
query_naissance = request.session.get('query_naissance', None)
You need 'django.contrib.sessions.middleware.SessionMiddleware' in your MIDDLEWARE_CLASSES.

Pass GET parameters through django's render() shortcut

I have a date filter that I am passing through several django views:
views.py
def event_list(request):
date_query = request.GET.get("date", str(default_event_date()))
d = datetime.strptime(date_query, "%Y-%m-%d").date()
# do stuff...
return render(request, "events/event_list.html", context)
But I would like to carry forward the GET parameters through the render().
I've found this answer for how to do this using reverse(), but render() doesn't take a url directly.
I suspect I need to add it back in to the request that is passed, but I'm not sure how to do this.
I think you are misunderstanding render. render’s job in life is to return an HttpResponse with content to the user from an HTML template and a context dictionary:
Combines a given template with a given context dictionary
and returns an HttpResponse object with that rendered text.
In contrast, redirect redirects the user to a new URL (i.e., so GET parameters can be included). Thus, if you use render, you have to preserve your GET parmeters manually. Of course, you can avoid this by adding date to the user’s session by doing something like:
from datetime import date, datetime
date_query = request.session.get('date')
if not date_query:
date_query = request.GET.get("date", default_event_date())
if not isinstance(date_query, date):
date_query = datetime.strptime(date_query, "%Y-%m-%d").date()
request.session['date'] = date_query
d = date_query
And this will let you “carry forward” your GET parameters to subsequent routes and views.

Django - dictionary passed in redirect is not showing in template

I'm trying to redirect my signup form to the same form after saving the values also I wanted to return a dictionary in the redirect response.
But the following code is not working.
urls.py
url(r'^signupform/$', views.render_signup, name='render_signup'),
url(r'^signup/$', views.sign_up_account_admin, name='sign_up_account_admin'),
views.py
def render_signup(request):
"""
"""
data_dict = {"some_keys":"some_values"}
return render(request, "admin.html", data_dict)
def sign_up_account_admin(request):
"""
"""
user = None
user, msg = save_form_data(request)
req_dict = {"msg": msg}
if user:
ret = redirect('homepage') #-- This works pretty fine
else:
ret = redirect('/signupform/', resp = req_dict) #-- This redirects but I don't get the `resp` Objects in the template
return ret
Html Temlpate
<div class="container">
=={{resp}}
===>>>>>>>{{resp.msg}}
</div>
And the Output HTML
<div class="container">
==
===>>>>>>>
</div>
You can't pass random kwargs to the redirect function.
The arguments passed to redirect are the same positional or keyword arguments which you would have passed had you used reverse() to generate the url. These arguments are used to reverse resolve the url.
As mentioned in the Django docs about using redirect() function.
By passing the name of a view and optionally some positional or
keyword arguments; the URL will be reverse resolved using the
reverse() method.
Now, as you are passing a hardcoded url, then the argument passed along with it will get discarded.
The recommended way to use redirect() with a hardcoded url as mentioned in Django docs is:
def my_view(request):
...
return redirect('/some/url/')
So, what you can do now is use to Django sessions or maybe pass a parameter in the url to access the value of resp in the render_signup view.
Solution-1 Using Django Sessions
One way is to use Django sessions to get the msg.
def sign_up_account_admin(request):
"""
"""
user = None
user, msg = save_form_data(request)
req_dict = {"msg": msg}
if user:
ret = redirect('homepage') #-- This works pretty fine
else:
request.session['resp'] = msg # set in session
ret = redirect('/signupform/')
return ret
Then in your render_signup view, you can do:
def render_signup(request):
"""
"""
resp = request.session.get('resp') # get the value from session
data_dict = {'resp': resp, ..}
return render(request, "admin.html", data_dict)
Solution-2 Pass it as url parameters
Another solution is to pass it in url as query parameters.
ret = redirect('/signupform/?resp=%s'%msg) # pass as query parameter
Then in the render_signup view, get this value from request.GET.
resp = request.GET.get('resp') # get the value of 'resp' from request.GET
data_dict = {'resp':resp, ..}
EDIT:
If you have multiple parameters to send which are in a dictionary, then you can use urllib.urlencode() to encode the dictionary and send it with the url.
encoded_string = urllib.urlencode(my_dict)
redirect('/signupform/?%s'%encoded_string) # attach the encoded string in the url
Then in your view, you can retrieve the keys of the dictionary from request.GET.
value1 = request.GET.get('key1')
value2 = request.GET.get('key2')

How to send two variables with html as a JSON in Django?

I want to render two different HTML samples and send it back as response to ajax request.
I have something like this in my view:
def getClasses(request):
User = request.user
aircomcode = request.POST.get('aircompany_choice', False)
working_row = Pr_Aircompany.objects.get(user=User, aircomcode=aircomcode)
economy_classes = working_row.economy_class
business_classes = working_row.business_class
economy = render_to_response('dbmanager/classes.html', {"classes": economy_classes}, content_type="text/html")
business = render_to_response('dbmanager/classes.html', {"classes": business_classes}, content_type="text/html")
return JsonResponse({"economy": economy,
"business": business})
With this I get the error:
django.http.response.HttpResponse object at 0x7f501dc56588 is not JSON serializable"
How can I do my task?
In js when I get the response I would like to insert received HTML into corespoding blocks. Like this:
$.ajax({ # ajax-sending user's data to get user's classes
url: url,
type: 'post',
data: {"aircompany_choice": aircompany_choice}, # send selected aircompanies for which to retrieving classes required
headers: {"X-CSRFToken":csrftoken}, # prevent CSRF attack
}).done (result) ->
add_booking_classes.find(".economy-classes").children(":nth-child(2)").html(result["economy"])
add_booking_classes.find(".business-classes").children(":nth-child(2)").html(result["business"])
Try Django's render_to_string :
economy = render_to_string('dbmanager/classes.html', {"classes": economy_classes})
business = render_to_string('dbmanager/classes.html', {"classes": business_classes})
render_to_string() loads a template, renders it and then returns the resulting string. You can then send these resulting strings as JSON.
Your final code now becomes:
from django.template.loader import render_to_string
def getClasses(request):
User = request.user
aircomcode = request.POST.get('aircompany_choice', False)
working_row = Pr_Aircompany.objects.get(user=User, aircomcode=aircomcode)
economy_classes = working_row.economy_class
business_classes = working_row.business_class
economy = render_to_string('dbmanager/classes.html', {"classes": economy_classes})
business = render_to_string('dbmanager/classes.html', {"classes": business_classes})
return JsonResponse({"economy": economy,
"business": business})
render_to_response is, as the name implies, for rendering a response. You don't want to do that; you want to render two templates, and put them into a JSON response. So use render_to_string.
You can send one in your context and one as where you want to render.

Categories