Pass GET parameters through django's render() shortcut - python

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.

Related

Passing data from post form to FileResponde view

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.

return to function from another function

i have a table which include all users and two columns at the end (Edit,Delete) and i just enabled the delete column, the issue is when i click on the delete icon the record will be deleted but the url will stuck on the delete function even if i used return render(request,'getUsersInfo.html') which is get all records function
Model Name: Users
urls:
from django.urls import path
from django.conf.urls import url
from . import views
urlpatterns = [
path('signup.html',views.signup,name=''),
path('getUsersInfo.html',views.getAllUsers,name=''),
url(r'^deleteUser/(?P<fullname>\D+)/$',views.deleteUser, name='deleteUser'),
# this is how to call a function without parameters url(r'^deleteUser/$',views.deleteUser, name='deleteUser'),
in the same view i have 3 functions (singup "add user", getAllUsers "get all the records to the table,deleteUser)
views:
def getAllUsers(request):
print("getAllUsers")
thesearchValue = ''
if 'SearchValue' in request.GET:
thesearchValue = request.GET['SearchValue']
print(request.GET['SearchValue'])
allUsers = User.objects.filter(fullname__icontains=thesearchValue)#all()
# return render(request,'getUsersInfo.html',{'allUsers':allUsers})
return render(request,'getUsersInfo.html',{'allUsers':allUsers})
else:
print("Empty")
allUsers = User.objects.all()
return render(request,'getUsersInfo.html',{'allUsers':allUsers})
def deleteUser(request,fullname):
print('delete the user')
todelete = User.objects.filter(fullname=fullname)
todelete.delete()
return render(request,'getUsersInfo.html')
Notice that i used return render(request,'getUsersInfo.html') which should call getAllUsers(request): but the url stuck on http://127.0.0.1:8000/deleteUser/John/
Rendering the same template as another view does not mean that you will somehow call other views. A template is nothing more than a tool to specify how to convert context data to a string, that is passed as HTTP response. You can use the same template in multiple views, and a view can render multiple templates.
You can make use of redirect(..) [Django-doc] to return a HTTP redirect response (302):
from django.shortcuts import redirect
def deleteUser(request,fullname):
print('delete the user')
todelete = User.objects.filter(fullname=fullname)
todelete.delete()
return redirect(getAllUsers)
Note: A GET request is not supposed to have side-effects, hence removing
objects when a user makes a GET request, is not compliant with the HTTP
standard. Therefore it might be better to remove a User with a POST request.

exposing data with django form get request

I'm building a small form on which I'm displaying some data in the table, addition to that I have two dropdown, with which you can select current data or year for the data you want to see in the table.
My question is how can I populate dropdown with current month and year, using django form get request, I'm little confused how to process this in my view, note that I'm using CBV FormView.
I've tried something like this
form.py
from django import forms
import datetime
class StatisticsForm(forms.Form):
"""TODO: Simple form with two field, one for year
other for month, so user can list Statistics for
current month and year.
:returns: TODO"""
invoice_month = forms.CharField(label="month", max_length=225)
invoice_year = forms.CharField(label="year", max_length=225)
def get_initial(self):
initial = super(StatisticsForm, self).get_initial()
initial["invoice_month"] = datetime.date.today()
initial["invoice_year"] = datetime.date.today()
return initial
and in my view I'm displaying table and I need to do the rest to.
view.py
from django.views.generic.edit import FormView
from .models import Rate
from statistics.forms import StatisticsForm
from statistics.services import StatisticsCalculation
class StatisticsView(FormView):
"""
TODO: We need to handle
Total Invoice - no matter how old, basically all of them
Current month Total Invoice
"""
template_name = "statistics/invoice_statistics.html"
form_class = StatisticsForm
def get_context_data(self, **kwargs):
context = super(StatisticsView, self).get_context_data(**kwargs)
def_currency = Rate.EUR
context["can_view"] = self.request.user.is_superuser
context["currency"] = def_currency
context["supplier_statistic"] = StatisticsCalculation.statistic_calculation(default_currency)
return context
When the FormView creates the actual form object, it gets the arguments to pass to the form from get_form_kwargs():
def get_form_kwargs(self):
"""
Returns the keyword arguments for instantiating the form.
"""
kwargs = {
'initial': self.get_initial(),
'prefix': self.get_prefix(),
}
if self.request.method in ('POST', 'PUT'):
kwargs.update({
'data': self.request.POST,
'files': self.request.FILES,
})
return kwargs
Notice how it's calling the get_initial() on itself (the view) rather than the form. It can't call it on the form because it's not initialized yet. Move your method into the view and you're good to go.
As a sidenote, use django.utils.timezone.now() as opposed to stdlib datetime.date.today() since it respects your django timezone settings and you may occasionally see some off-by-one quirks otherwise.
Edit: You should also update your form to use ChoiceField, and set the defaults with timezone.now().month and timezone.now().year.
Happy coding.

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.

print page generation time

how would I print the time it took to render a page to the bottom of my site in django? i'm not sure of the application flow of django, so I don't know how this would work.
You might be interested in django-debug-toolbar, which includes a request timer and lots of other useful info for debugging things like this.
At the beginning of your view handler, save the current date/time in a variable say time_start and pass that to the template context which renders the page.
Then define a custom template filter that will create timedelta based on datetime.now() value and the original datetime passed in as a parameter like so:
from datetime import datetime
from django import template
register = template.Library()
#register.filter
def get_elapsed(time_start):
return str(datetime.now() - time_start)
Then in your template, simply display:
...
{{ time_start|get_elapsed }}
...

Categories