in my custom templates pagination is applied on it. the list that show on page is much bigger than i used pagination on it. the limit to display the list is wroking properly but when i click on the next button than it go on the else condition.
views.py :-
#csrf_exempt
def search(request):
if request.method == 'POST':
getchoice = request.POST['userchoice']
getfirstdate = request.POST['firstdate']
getseconddate = request.POST['seconddate']
if getchoice == '0':
getdata = applicationform.objects.filter(date__gte=getfirstdate , date__lte=getseconddate)
##### PAGINATION
searchpagination = Paginator(getdata ,5)
page = request.GET.get('searchpage')
try:
searchcontacts = searchpagination.page(page)
except PageNotAnInteger:
searchcontacts = searchpagination.page(1)
except EmptyPage:
searchcontacts = searchpagination.page(searchpagination.num_pages)
if getdata:
return render_to_response('registration/search_page.html', {'getdata':getdata ,'getchoice':getchoice ,'searchcontacts': searchcontacts})
else:
return HttpResponse('NO ITEMS FOUND ON THIS DATE')
else :
return render_to_response('registration/search_page.html')
custom template:-
{% if searchcontacts.has_previous %}
PREVIOUS
{% endif %}
{% if searchcontacts.has_next %}
NEXT
{% endif %}
Click on NEXT will be GET request and hence it is going in else section.
To continue search for next page, either you need to store search parameters in the session or pass it through url. And then use that in filter() query.
Related
i am trying to get nearby places using googleplaces with python and flask
i am getting this error: (UnboundLocalError: local variable 'place_name' referenced before assignment)
here is my code:
#app.route('/Search', methods=['POST', 'GET'])
#login_required
def Search():
if request.method == 'POST':
query_result = google_places.nearby_search(
lat_lng={'lat':31.7917, 'lng' : 7.0926},
radius=500,
types=[types.TYPE_SHOPPING_MALL] or [types.TYPE_STORE])`
if query_result.has_attributions:
print(query_result.html_attributions)
for place in query_result.places:
place.get_details()
place_name = place.name
print(place.name)
place_rating = place.rating
print(place.rating)
place_location = place.get_location
print(place.get_location)
for photo in place.photos:
photo.get(maxheight=500, maxwidth=500)
photo.mimetype
photo.url
photo.filename
photo.data
return render_template('Search.html', place_name, place_rating, place_location)
else:
return render_template('Search.html')```
#Note: i am new to python in general
return render_template('Search.html', place_name, place_rating, place_location)
The above isn't valid syntax. When you pass the details to the template, you need to do it as:
return render_template('Search.html', name = place_name,
rating = place_rating, location = place_location)
The variables name, rating and location will then be accessible in the template as {{name}}, {{rating}} and {{location}}.
However, the way you have the for loops laid out means the first time the return statement is reached, it will stop the loop and return the template with these variables.
Perhaps this is what you want, but you may wish to pass query_result to the template, and implement a Jinja2 for loop in the template to print out the various place details. You would remove the for loops and replace that whole block with:
return render_template('Search.html', all_places = query_result)
Then in the template something like:
{% if all_places %}
{% for place in all_places %}
<p><b>{{place.name}}</b> has a rating of <u>{{place.rating}}</u></p>
{% endfor %}
{% else %}
<p>No places found.</p>
{% endif %}
I am creating a list containing items from two different models and passing it to my template. Here is my view function:
def newsfeed(request):
Text = Post.objects.all().order_by('-Timestamp')
Images = ImagePost.objects.all().order_by('-Timestamp')
Posts = []
while True:
if Text[0].Timestamp >= Images[0].Timestamp:
Posts.append(Post.objects.get(id=Text[0].id))
Text = Text.exclude(id=Text[0].id)
else:
Posts.append(ImagePost.objects.get(id=Images[0].id))
Images = Images.exclude(id=Images[0].id)
if len(Text) == 0:
for i in Images:
Posts.append(i)
break
elif len(Images) == 0:
for i in Text:
Posts.append(i)
break
print(Posts[:6])
return render(request, 'campaign/newsfeed.html', {
"posts": Posts,
})
I need a way to find out which model each item in the list was from in the template so that I know how to render the item. Is there a way to tell without sending further data to the template?
You can give both models (or their common super class) a method:
def model_name(self):
return self.__class__.__name__
And in the template, you can check:
{% for p in posts %}
{% if p.model_name == 'ImagePost'%}
# ...
{% endif%}
{% endfor %}
If these are models from third-party packages, you can always just set attributes in the view:
for i in Images:
i.model_name = 'ImagePost'
Posts.append(i)
My first foray into Django, allows the user to input a day of the week, and searches my database for restaurants open on that given day. Right now, the restaurant objects (Resto) have a days_open attribute, with each day separated by a comma (Monday, Tuesday, etc...).
When I input a day, the resulting page only displays the title and '[]' and I can't seem to get it to return the list of Resto objects. What is displaying the square brackets, and how do I go about fixing it to display the results of the search?
The code is below- my apologies if I neglected to include any relevant bits.
my forms.py:
from django import forms
from .models import Resto
class RestoSearch(forms.ModelForm):
class Meta:
model = Resto
fields = ('title', 'description', 'opening_hour', 'closing_hour')
models.py:
from django.db import models
class Resto(models.Model):
title = models.CharField(max_length=300)
description = models.TextField()
opening_hour = models.TimeField(auto_now=False, auto_now_add=False, null=True)
closing_hour = models.TimeField(auto_now=False, auto_now_add=False, null=True)
days_open = models.TextField(blank=True)
views.py:
from django.shortcuts import render
from django.http import Http404
from django.shortcuts import HttpResponse
from belize.models import Resto
from django.core.exceptions import *
from .forms import RestoSearch
def index(request):
return render(request, 'form.html')
def search(request):
form = RestoSearch()
if request.method == 'POST':
search_id=request.POST.get('textfield', None)
try:
#I think this is where my problem is
available = Resto.objects.filter(days_open = search_id)
html = ("<H1>Hello</H1>", available)
return HttpResponse(html)
except Resto.DoesNotExist:
return HttpResponse("Please try another day")
else:
return render(request, 'belize/form.html')
def restaurant_detail(request, id):
try:
restaurant = Resto.objects.get(id=id)
except Resto.DoesNotExist:
raise Http404('This restaurant does not exist')
return render(request, 'belize/restaurant_detail.html', {
'restaurant': restaurant,
})
template form.html:
<form method="POST" action="/search/">
{% csrf_token %}
<input type="text" name="textfield">
<button type="submit">Enter a day of the week</button>
</form>
I presume what you are trying to show is the RestoForm in that case the index method is not correct. It should be
def index(request):
form = RestoForm()
return render(request, 'form.html', {'form': form })
And then your template should change as
<form method="POST" action="/search/">
{% csrf_token %}
{{ form }}
<button type="submit">Enter a day of the week</button>
</form>
For additional details please see the examples at https://docs.djangoproject.com/en/1.9/topics/forms/#the-template
The [] means that your .filter() returned no results, its not surprising as you have a few issues with your code, lets start from the top:
You are declaring a form that you never use.
You are trying to catch an exception that is never raised by .filter()
You filter condition will only work for exact matches.
I've annotated your code as well:
def search(request):
form = RestoSearch() # You aren't using this form anywhere in your code?
if request.method == 'POST':
# Where is 'textfield' coming from?
search_id = request.POST.get('textfield', None)
try:
# If search id is "Tuesday", and a restaurant is
# open on monday and tuesday, so it has "Monday,Tuesday"
# in the days_open field, then this search will not
# return any results, because its looking for an exact
# match
available = Resto.objects.filter(days_open=search_id)
html = ('<H1>Hello World</H1>', available)
return HttpResponse(html)
except Resto.DoesNotExist:
# This exception is not raised by .filter(),
# .filter() will return an empty list, [] if no results are found
# so this entire try/except is not doing anything
return HttpResponse("Please try another day")
else: # in your code, this else is not indented correctly
return render(request, 'belize/form.html')
So there is a lot going on here, lets try something simple, starting with the template:
{% if results %}
{% for restaurant in results %}
{{ restaurant }}
{% endfor %}
{% else %}
Sorry, no results for your search. Try again.
{% endif %}
<form>
{{ form }}
<input type="submit" name="Search" />
</form>
Next, the search form:
class SearchForm(forms.Form):
search_field = forms.CharField('Search', strip=True)
Finally the view:
from django.db.models import Q
def search(request):
form = SearchForm(request.GET)
results = [] # Set results to an empty list
if form.is_valid():
needle = form.cleaned_data['search_field'].capitalize()
results = Resto.objects.filter(Q(days_open__startswith='{},'.format(needle)) |
Q(days_open__endswith=',{}'.format(needle)) |
Q(days_open__contains=',{},'.format(needle)) |
Q(days_open='{},'.format(needle)) |
Q(days_open='{}'.format(needle)))
return render(request, 'search.html', {'results': results, 'form': form})
Lets assume the user entered 'Thursday' as a search field. In this view you are searching for all restaurants whose days_open field:
Either starts with Thursday, or
Ends with ,Thursday or
Contains ,Thursday, in the middle or
Has the value Thursday, or
Has the value Thursday
Your template will then only show the results if there are any values to display; since an empty list [] is false, then the {% if results %} condition will fail, so on empty lists the template will display the error notice instead.
In your view, you only do the database check if someone enters something in the search field, that's what if form.is_valid(): does. In django, by default all form fields are required - so a blank form will return an error. Using this trick, we make sure we only search if someone enters a value in the search box.
The main action happens with all the Q() calls. A Q object is a way to do multiple queries and chain them together. It is used whenever you want to do an "or" or "and" type query. Our search is an "or" type query, because we want to return any results if the value in days_open matches any number of conditions.
Can anyone help me with the below? I'm reading 'how to tango with django' project and stuck here.
I want a html form to revert back to a view function(add_page).
<h1>Add a Page</h1>
{% if category %}
<form id="category_form" method="post" action="/rango/category/{{category.slug}}/add_page/">
{% endif %}
This is my url map
urlpatterns = patterns('',
url(r'^$',views.index, name = 'index'),
url(r'^about/$',views.about, name = 'about'),
url(r'^category/(?P<category_name_slug>[\w\-]+)/$',views.category,name = 'category'),
url(r'^add_category/$', views.add_category, name = 'add_category'),
url(r'^category/(?P<category_name_slug>[\w\-]+)/add_page/$',views.add_page, name ='add_page'),
)
and my veiws.add_page function
def add_page(request,category_name_slug):
try:
cat = Category.objects.get(slug = category_name_slug)
except :
cat = None
if request.method == 'POST':
form = PageForm(request.POST)
if form.is_valid():
if cat:
page = form.save(commit = False)
page.category = cat
page.views = 0
page.save()
return redirect('/rango')
else:
print (form.errors)
else:
form = PageForm()
context_dict = {'form':form,'category':cat}
return render(request, 'rango/add_page.html',context_dict)
the submit button doesnt seem to be taking to post data to the requested url. Please let me know where i am going wrong?
If you want to redirect to the same page
you should probably call
return redirect('add_page', category_name_slug=page.category)
or maybe use something like
return redirect(request.build_absolute_uri())
in the POST section of your code.
request methods
redirect() options
EDIT: To clarify the 'return redirect('rango/')' is not pointing to anything in the url mapping in the question.
I have created an Employee management system using Django. I have done a filtering method in it and is based on a choice selected from a drop down menu and a text input. the filtering is working fine. On the first page it gives the entire employee list which can be shown in both ascending and descending order. On the same page is given the filtering method. The filtered data is shown in another page. Now i want to give a button on the filtered data page, clicking on that button shows the data in ascending/descending. I have written a separate function for ascending and descending in views for the full employee listing. How can it be used for this functionality. I will paste my code here. Please help me to find a solution as i am new to django programming.
I have given 2 separate images for ascending and descending.I want it this way: Clicking on 1 image lists in ascending order; and clicking on other image lists it in descending order.
Filter()
def filter(request):
val3=''
if request.GET.has_key('choices'):
val2=request.GET.get('choices')
if request.GET.has_key('textField'):
val3=request.GET.get('textField')
if request.POST:
val2=request.POST.get('choices')
val3=request.POST.get('textField')
if val2=='Designation':
newData = EmployeeDetails.objects.filter(designation=val3)
flag=True
elif val2=='Name':
newData = EmployeeDetails.objects.filter(userName__icontains=val3)
flag=True
elif val2=='EmployeeID':
newData = EmployeeDetails.objects.filter(employeeID=val3)
flag=True
elif val2=='Project':
newData = EmployeeDetails.objects.filter(project=val3)
flag=True
elif val2=='DateOfJoin':
newData = EmployeeDetails.objects.filter(dateOfJoin=val3)
flag=True
else:
return HttpResponseRedirect('/employeeList/')
#tableList = EmployeeDetails.objects.all()
paginator = Paginator(newData, 10)
try:
page = int(request.GET.get('page', '1'))
except ValueError:
page = 1
try:
contacts = paginator.page(page)
except (EmptyPage, InvalidPage):
contacts = paginator.page(0)
return render_to_response('filter.html',{'newData':newData,'emp_list': contacts,'val2':val2,'val3':val3,'flag':flag})
filter.html
<div>
Employees List
<a STYLE="text-decoration:none" align=center href="http://10.1.0.90:8080/sortAscend/ "> <img src="/static/sort_asc.gif " border="1" height="12" /> </a>
<h4 align="left">
{%for data in newData%}
<a STYLE="text-decoration:none" href ="http://10.1.0.90:8080/singleEmployee/{{data.id}}?choices={{val2}}&textField={{val3}}&flag=1 ">
{{ data.userName}}<br>
{%endfor%}
</h4>
</div>
ascending and descending functions
def sortAscend(request):
tableList = EmployeeDetails.objects.all().order_by('userName')
paginator = Paginator(tableList, 12)
try:
page = int(request.GET.get('page', '1'))
except ValueError:
page = 1
try:
contacts = paginator.page(page)
except (EmptyPage, InvalidPage):
contacts = paginator.page(0)
return render_to_response('sortAscend.html', {'emp_list': contacts})
#Method for listing the employees in descending order
def sortDescend(request):
tableList = EmployeeDetails.objects.all().order_by('-userName')
paginator = Paginator(tableList, 12)
try:
page = int(request.GET.get('page', '1'))
except ValueError:
page = 1
try:
contacts = paginator.page(page)
except (EmptyPage, InvalidPage):
contacts = paginator.page(0)
return render_to_response('sortDescend.html', {'emp_list': contacts})
sortAscending.html
{%for emp in emp_list.object_list%}
<tr> <td><a STYLE="text-decoration:none" href ="http://10.1.0.90:8080/singleEmployee/{{emp.id}} "> {{ emp.userName }} </a></td> </tr><td>
{%endfor%}
Another alternative to handling sorting in the view level is to do it on the templates. For this reason, you might want to checkout jquery tablesorter (since you are using a table in the display as well). It handles sorting in ascending/descending order.
So if you have the results after filtering that is ready to be displayed to a page, say filtered_results.html, you can do it like this.
<!-- filtered_results.html -->
<head>
...
<script type="text/javascript" src="/path/to/jquery-latest.js"></script>
<script type="text/javascript" src="/path/to/jquery.tablesorter.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$("#myTable").tablesorter();
});
</script>
</head>
<body>
<table id="myTable">
<thead><tr><th>Some-Label</th></tr></thead>
<tbody>
{% for emp in emp_list.object_list %}
<tr><td>{{emp.userName}}</td></tr>
{% endfor %}
</tbody>
</table>
</body>
Clicking on the cell of 'Some-Label' will toggle the sorting in ascending/descending order.
Furthermore, it has a plugin for handling pagination. Check out this link for the demo.
I'm not sure I get the question, but if you want to apply the sorting to the filtered objects, you might want to add some sort of caching (different from django's builtin caching), that stores the filtered queryset and sort that. Or you can pass the filter option around using django's session management and redo the sorting query. This would require to refactor filter so the if/elif chain is independant of that view and returns the filtered queryset.
ex:
def filterHandler(request):
val3=''
if request.GET.has_key('choices'):
val2=request.GET.get('choices')
if request.GET.has_key('textField'):
val3=request.GET.get('textField')
if request.POST:
val2=request.POST.get('choices')
val3=request.POST.get('textField')
newData , flag = filter(val2, val3)
if newData is None:
return HttpResponseRedirect('/employeeList/')
#tableList = EmployeeDetails.objects.all()
paginator = Paginator(newData, 10)
try:
page = int(request.GET.get('page', '1'))
except ValueError:
page = 1
try:
contacts = paginator.page(page)
except (EmptyPage, InvalidPage):
contacts = paginator.page(0)
request.session['val2'] = val2
request.session['val3'] = val3
return render_to_response('filter.html',{'newData':newData,'emp_list': contacts,'val2':val2,'val3':val3,'flag':flag})
def filter(val2, val3):
newData = None
flag = False
if val2=='Designation':
newData = EmployeeDetails.objects.filter(designation=val3)
flag=True
elif val2=='Name':
newData = EmployeeDetails.objects.filter(userName__icontains=val3)
flag=True
elif val2=='EmployeeID':
newData = EmployeeDetails.objects.filter(employeeID=val3)
flag=True
elif val2=='Project':
newData = EmployeeDetails.objects.filter(project=val3)
flag=True
elif val2=='DateOfJoin':
newData = EmployeeDetails.objects.filter(dateOfJoin=val3)
flag=True
return newData, flag
Now your sorting methods can get the filter values that was passed originally. Optionally you can add them as get parameters to the views url also.