I have 3 database model - Semester, Section and Notecard
The Notecard model has a "Known" field that I use to classify the Notecard objects into "piles" as Known (1) or Unknown (0):
class Notecard(models.Model):
notecard_name = models.CharField(max_length=50)
notecard_body = models.TextField()
section = models.ForeignKey(Section)
known = models.BooleanField()
I have two views - known_list and unkown_list that displays the corresponding piles (known_list below for reference):
def known_list(request, section_name):
try:
section = Section.objects.get(section_name__iexact = section_name)
except Section.DoesNotExist:
raise Http404
known_list = Notecard.objects.filter(known=1, section=section)
paginator = Paginator(known_list, 1)
if known_list:
try:
page = int(request.GET.get('page', '1'))
except ValueError:
page = 1
try:
known = paginator.page(page)
except (EmptyPage, InvalidPage):
known = paginator.page(paginator.num_pages)
context = RequestContext(request)
return render_to_response('notecards/known.html', {"known": known}, context_instance=context)
else:
url = reverse('notecard_list', kwargs={'section_name': section_name})
return HttpResponseRedirect(url)
This view brings in the section_name from the previous view to display all the Notecard objects that are in the section that was clicked on, and in the known pile.
In the template below, you can see that I paginate the notecards to one a page:
{% extends "base.html" %}
{% block content %}
<h1 class='title'>NoteCards!</h1>
{% for notecard in known.object_list %}
<h1 class='notecard'>{{ notecard.notecard_name }}</h1>
<h3 class='notecard'>{{ notecard.notecard_body }}</h3>
{% endfor %}
<div class="pagination">
<span class="step-links">
{% if known.has_previous %}
<a class="navlink" href="?page={{ known.previous_page_number }}">previous</a>
{% endif %}
<span class="current">
Page {{ known.number }} of {{ known.paginator.num_pages }}
</span>
{% if known.has_next %}
<a class="navlink" href="?page={{ known.next_page_number }}">next</a>
{% endif %}
</span>
</div>
{% endblock %}
urls.py
urlpatterns += patterns('',
url(r'^(?P<section_name>[\w|\W]+)/unknown/$', unknown_list, name="unknown_list"),
url(r'^(?P<section_name>[\w|\W]+)/known/', known_list, name="known_list"),
url(r'^semester/(?P<semester_name>[\w|\W]+)/', section_list, name="section_list"),
url(r'^section/(?P<section_name>[\w|\W]+)/', notecard_list, name="notecard_list"),
url(r'^notecard/(?P<notecard_name>[\w|\W]+)/', notecard_detail, name="notecard_detail"),
url(r'^$', semester_list, name="semester_list"),
)
That said, I would like to add a "Send to Unknown" button that will allow users to send the notecard whose page they are currently on to the unknown pile (Simply changing the known field to = 0, removing the notecard from the pagination list, and moving to the next page in the pagination).
I have tried replicating my new_notecard view which contains a full form of the model, but I was unable to figure out how to update a single field.
I have also tried using queryset.update() but was unable to figure out how to capture the pk from the specific notecard.
I've been trying to figure this out on my own for over a month, but I've been unsuccessful. Thank you in advance.
EDIT:
It seems like my hang up is pulling the pk of the notecard on each page of the pagination. For example, if I am on page 3 of the pagination - when the "Send to Unknown" button is pushed, how do I identify that notecard in my view and update it from known (1) to unknown (0)
you must create a specific view with a specific url to handle this, for example:
# urls.py
url(r'^movetounknown/(?P<notecard_id>[\w|\W]+)/', notecard_move_to_unknown)
# views.py
#require_POST
def notecard_move_to_unknown(request, notecard_id):
notecard = Notecard.objects.get(pk=notecard_id)
notecard.known = False
notecard.save()
return HttpResponseRedirect(request.POST['next'])
# template
{% for notecard in known.object_list %}
<h1 class='notecard'>{{ notecard.notecard_name }}</h1>
<h3 class='notecard'>{{ notecard.notecard_body }}</h3>
<form action="{% url views.move_to_unknown notecard.pk %}" method="post">
<input type="hidden" name="next" value="{% url known_list known.section.section_name %}?page={{known.paginator.number}}"/>
<input type="submit" value="Move to unknown list"/>
</form>
{% endfor %}
You also can pass the notecard id as a post parameter.
The next parameter tells where to go after the change, here I choose the same page of the known list because once the current card is removed the next one is at this index
Capturing the pk of a specific notecard object can be done by defining a specific url for that notecard. For example:-
# urls.py
url(r'^notecard/(?P<notecard_id>\d+)/$',
'notecard',
name='notecard'),
# corresponding views.py
def notecard(request, note_card_id):
notecard = get_object_or_404(Notecard, pk=note_card_id)
template = 'notecard/notecard.html'
template_vars = {'notecard': notecard}
render(request, template, template_vars)
# notecard/notecard.html
<h2>{{ notecard.notecard_name }}</h2>
<p>{{ notecard.notecard_body }}</p>
You can also define a form with the notecard id/pk being a hidden field for submission and updating into your database (and of course, you will need to update your view function correspondingly).
In essence, to update a specific notecard object, you will simply do in your view function (with form submission or, if you prefer, a pure ajax implementation in your listing page) like this
notecard.known = False
notecard.save()
Related
I'm building an application that contains a list of meals, where each meal has various filters, a price, and a rating.
The filters are like tags; the user can select multiple, and the page only shows the meals that have the selected filters.
The price and ratings are integers, and the user can sort by either price or rating, which sorts the meals (cheapest -> most expensive for price, highest -> lowest for rating).
I have built two forms in Django, one for filters and one for sorting, and they both work on their own. However, let's say I submit the sorting form to sort by price; when I do this, it does sort by price, but it removes all of the prior filters I had submitted.
Below are the important pieces of code relevant to this problem:
views.py
def meals(request):
meal_list = Meal.objects.all()
tags = Tag.objects.all()
reviews = Review.objects.all()
filter_form = FilterForm(request.GET or None)
sorting_form = SortingForm(request.GET or None)
sort = ""
active_filters = []
if filter_form.is_valid():
tags = filter_form.cleaned_data.get('tags')
for tag in tags:
meal_list = meal_list.filter(tags__name=tag)
active_filters.append(tag)
if sorting_form.is_valid():
sort = sorting_form.cleaned_data.get('sort')
if sort == "price":
meal_list = meal_list.order_by('price')
else:
meal_list = meal_list.order_by('-rating')
paginator = Paginator(meal_list, 8)
page_number = request.GET.get('page')
meals_on_page = paginator.get_page(page_number)
context = {"meal_list": meal_list,
"distances": distances,
"tags": tags,
"reviews": reviews,
"active_filters": active_filters,
"meals_on_page": meals_on_page,
"filter_form": filter_form,
"sorting_form": sorting_form,
}
return render(request, 'meals/meals.html', context)
forms.py
from django import forms
# Tag is the model for the filters, it is just a ManyToManyField that contains a name attribute
from .models import Tag
class FilterForm(forms.Form):
tags = forms.ModelMultipleChoiceField(
queryset=Tag.objects.all(), widget=forms.CheckboxSelectMultiple)
class SortingForm(forms.Form):
SORT_CHOICES = [
('price', 'Price'),
('rating', 'Rating'),
]
sort = forms.ChoiceField(choices=SORT_CHOICES, widget=forms.Select)
meals.html
<form method="get">
{% for field in filter_form %}
{{ field.as_widget }} {{ field.label_tag }}
{% endfor %}
<input type="submit" value="Filter">
</form>
<form method="get">
{% for field in sorting_form %}
{{ field.as_widget }}
{% endfor %}
<input type="submit" value="Sort">
</form>
I have sadly way too long trying to fix this, and the closest I got was using get_copy = request.GET.copy() and then trying to manually add the URL parameters back onto the end of a URL after a form was submitted. However, none of my approaches using this seemed to work.
Thanks in advance for the help!
In your Django view, you can access the current URL parameters using the request object's GET attribute. To maintain these parameters when either form is submitted, you can include them in the form action attribute in your template.
For example, in your template, you can update the form action attribute to include the current URL parameters like this:
<form method="get" action="{% url 'meals' %}?{{ request.GET.urlencode }}">
This will append the current URL parameters to the form action, so when the form is submitted, the current parameters will be included in the request.
In your view, you can then access these parameters using the request.GET dictionary. You can use these parameters to filter and sort your queryset accordingly before rendering the template.
Note: you should also check if the forms are valid before processing the form data to avoid unexpected behavior.
Also, you can use Django's forms.HiddenInput() to include the current parameters on your forms as hidden fields, that way you don't need to update form's action attribute.
I ended up solving this after soaking (way too many) more hours into it.
The way I did this was to build my own dictionary of parameters, and then to pass these parameters into the forms as hidden inputs.
Below is the added code:
views.py
get_copy = request.GET.copy()
parameters = get_copy.urlencode()
get_copy.pop('page', None)
param_list = parameters.split("&")
param_dict = defaultdict(list)
for param in param_list:
try:
key, value = param.split("=")
except ValueError:
# Handle the case where there's no "=" in the parameter string
key = param
value = ""
if key == "tags":
param_dict[key].append(int(value))
else:
param_dict[key].append(value)
# Django requires me to turn dictionary to items here, rather than in the template
param_dict_items = param_dict.items()
meals.html
<form method="get" action="{% url 'meals' %}?{{ request.GET.urlencode }}">
{% for field in filter_form %}
{{ field.as_widget }} {{ field.label_tag }}
{% endfor %}
{% for key, value_list in param_dict_items %}
{% if key != 'tags' %}
{% for value in value_list %}
<input type="hidden" name="{{ key }}" value="{{ value }}">
{% endfor %}
{% endif %}
{% endfor %}
<input type="submit" value="Filter">
<form method="get" action="{% url 'meals' %}">
{% for field in sorting_form %}
{{ field.as_widget }}
{% endfor %}
{% for key, value_list in param_dict_items %}
{% if key != 'sort' %}
{% for value in value_list %}
<input type="hidden" name="{{ key }}" value="{{ value }}">
{% endfor %}
{% endif %}
{% endfor %}
<input type="submit" value="Sort">
I'm building a Netflix like website for my Devops course. I made a Python list of dictionaries (Mockfilms) to define my films, and want to populate a database (Ratings) with reviews in preparation for sending data in the format :filmid: :userid: :rating: to a recommendation engine.
My index page is a list of film images with a link to a review form under each one. I want each review form to appear on a different url (/review/ID where ID is saved in mockfilms as oid). In order to do this I want to access mockfilms.oid, then pass it to the view function to make the url for the form. Once the form is complete I then want to add this ID to the Ratings database. Here is what I have so far:
Index:
{% extends "base.html" %}
{% block content %}
<h1>Hello, {{ current_user.username }}! Welcome to our extensive video library:</h1>
{% for film in mockfilms %}
{% set ID = film.oid %}
<div>
<a href = {{ film.video }}>
<img src = {{ film.image }} alt = "doh" style = "width:200px;height:200px;border:0;">
</a>
</div>
<div>
">Leave a review here!
{% endfor %}
{% endblock %}
Route:
#app.route('/review/<ID>', methods = ['GET', 'POST'])
#login_required
def review(ID):
form = ReviewForm()
if form.validate_on_submit():
review = Ratings(User_id = current_user.id, Score_given = form.score.data, Film_id = ID)
db.session.add(review)
db.session.commit()
flash('Thanks for your review')
return redirect(url_for('index'))
return render_template('review.html', title='Review Page', form=form)
The following error is what I get when I run it:
File "/home/jc/Desktop/Lokal/DevopsAssig/microblog/Kilfinnan/lib/python3.5/site-packages/werkzeug/routing.py", line 1768, in build
raise BuildError(endpoint, values, method, self)
werkzeug.routing.BuildError: Could not build url for endpoint 'review'. Did you forget to specify values ['ID']?
From this I assume that the issue is with the ID variable within this template. My searchings and learnings led me to believe that {% set %} in the index template would let me declare the ID variable and then use it in the dynamic.
Try this:
{% block content %}
<h1>
Hello, {{ current_user.username }}!
Welcome to our extensive video library:
</h1>
{% for film in mockfilms %}
<div>
<a href="{{ film.video }}">
<img src="{{ film.image }}" alt="doh" style="width:200px;height:200px;border:0;" />
</a>
</div>
<div>
<a href="{{ url_for('review', ID=film.oid) }}">
Leave a review here!
</a>
</div>
{% endfor %}
{% endblock %}
Ultimately your solution was quite close, but it is not necessary to use the Jinja set command when you need to pass the variable into url_for() function using the keyword for the parameter. You could still do it using {% set ID = film.oid %} but it would be a bit superfluous.
Try to provide key=value arguments into your url_for function.
Something like this
">Leave a review here!
Also Flask have a great documentation, Flask docs
Okay so this is first time using pagination with Django and I am trying to prevent it from reloading my view on each page turn.
I'm handling the pagination in the view like this:
page = request.GET.get('page', 1)
print page
paginator = Paginator(list(od.iteritems())[:24], 12)
try:
data = paginator.page(page)
except PageNotAnInteger:
data = paginator.page(1)
except EmptyPage:
data = paginator.page(paginator.num_pages)
print data
save_query_form = SaveQueryForm(request.POST or None)
#if request.method == 'POST':
if save_query_form.is_valid():
profile = save_query_form.save(commit=False)
profile.user = request.user
profile.save()
context = {
"title":"Search",
'data': data,#list(od.iteritems()),
'tools': od_tools.iteritems(),
'methods': od_methods.iteritems(),
'data4': od_data.iteritems(),
'search_phrase': " ".join(instanceValuesString),
'json_dump': js_data,
'form': save_query_form,
}
return render(request, 'results.html', context)
and the pagination is handled in the html:
{% if data.has_other_pages %}
<div id='page-slide'>
<ul class="pagination" start='$offset'>
{% if data.has_previous %}
<li>«</li>
{% else %}
<li class="disabled"><span>«</span></li>
{% endif %}
{% for i in data.paginator.page_range %}
{% if data.number == i %}
<li class="active"><span>{{ i }} <span class="sr-only">(current)</span></span></li>
{% else %}
<li>{{ i }}</li>
{% endif %}
{% endfor %}
{% if data.has_next %}
<li>»</li>
{% else %}
<li class="disabled"><span>»</span></li>
{% endif %}
</ul>
</div>
{% endif %}
The issue that I am having is that whenever I switch to another page my entire view will run again and the data will does not reflect the original search query and instead defaults to an empty query.
I was wondering if there is a simple way to either handle pagination dynamically or prevent the page reload when toggling between pages?
Any help is appreciated, thanks.
Update Search Form:
<form action="{% url 'results-view' %}" method="POST" class="autocomplete-me ui-widget" id="myform" >
{% csrf_token %}
<div class="ui-widget" style="text-align:center;">
<input type="text" id="id_q" name="q" placeholder="{{ search_phrase }}">
<br></br>
<div style="text-align:center;" id='adjust-button'>
<input type='submit' class='btn btn-secondary btn-lg' id ='search-btn' value='Search'/>
<a class='btn btn-secondary btn-lg' id ='clear-btn' href="{% url 'inital' %}">Clear</a>
</div>
</div>
</form>
You noted in a comment that you get your search value with instanceValuesString = request.POST.get(u"q").encode('utf-8').strip(). As one commenter correctly pointed out, this means that when you click your "next page" links (making a GET request), your view doesn't receive the information it needs to return search results.
One way to fix this would be to get your instanceValuesString from a GET request instead of a POST request. For instance, perhaps your list view is at
http://example.com/StuffList
You could look for URLs that provide a search querystring:
http://example.com/StuffList?search=goodstuff
And then grab that in your view:
instanceValuesString = request.GET.get('search', None)
if instanceValuesString is not None:
#you have detected a search query; filter results, process request, etc.
One side effect here is that the way you currently construct your next/previous page URLs will break. Consider the example search URL; your current template would construct a link for page 2 like so:
http://example.com/StuffList?search=goodstuff?page=2
This won't work; it should be &page=2. Fortunately there's an easy fix; check out the second answer to this question: Altering one query parameter in a url (Django). Using that url_replace instead of constructing those links with the basic url template tag will solve this part of the issue.
This is very much simplified with below package
http://django-simple-pagination.readthedocs.io/en/latest/
I've been trying to figure this out for days and was unable to find any useful information online.
What I am trying to do is paginate objects from my model after filtering them using a drop down menu and supplying the data to python via AJAX. I know where the problem is but I am not sure how to solve it. I have two templates, first one is:
entry_index.html:
{% extends 'main/base.html' %}
<form action="" method="get" accept-charset="utf-8">
<select class="selectpicker" name="times" onchange="FilterCategories()" id="times">
<option value="1">last 24 hours</option>
<option value="30">past month</option>
<option value="365">past year</option>
<option value="10000">all time</option>
</select>
</form>
<ul id="all-games" class="list-unstyled">
{% include page_template %}
</ul>
The template that is being included in the above template is entry_index_page.html:
{% if objects %}
{% for object in objects %}
do something
{% endfor %}
<div class="pagination">
<span class="step-links">
{% if objects.has_previous %}
previous
{% endif %}
<span class="current">
Page {{ objects.number }} of {{ objects.paginator.num_pages }}.
</span>
{% if objects.has_next %}
next
{% endif %}
</span>
</div>
urls.py:
url(r'^$', views.entry_index, name='index')
views.py:
def entry_index(
request,
template='entry_index.html',
page_template='entry_index_page.html'):
date_from = timezone.now() - timezone.timedelta(days=1)
obj_list=Object.objects.filter(submitted__gte = date_from).order_by('-votes')
message=[]
context = {
'objects': obj_list,
'page_template': page_template}
if request.is_ajax():
template = page_template
message = []
if request.method == "GET":
time_range = request.GET.get('time_range')
if time_range is not None and time_range != u"":
time_range = request.GET['time_range']
date_from = timezone.now() - timezone.timedelta(days=int(time_range))
obj_list= Object.objects.filter.filter(submitted__gte=date_from)
paginator = Paginator(obj_list, 2)
page = request.GET.get('page')
try:
objects= paginator.page(page)
except PageNotAnInteger:
objects= paginator.page(1)
except EmptyPage:
objects= paginator.page(paginator.num_pages)
context.update({"message":message,"objects":objects})
return render_to_response(
template, context, context_instance=RequestContext(request))
ajax.js:
function FilterCategories() {
var timePosted = document.getElementById('times');
$.ajax({
type: "GET",
url: "",
data: {
'time_range': timePosted.value,
'csrfmiddlewaretoken': $("input[csrfmiddlewaretoken]").val()
},
success: filterResults,
dataType: 'html'
});
}
Now to explain what I think is going on and hopefully someone can help me find a solution.
When the home page is loaded (entry_index.html) the model gets filtered based on the first option in the drop down menu (i.e. value="1", which is filtering for the data entries submitted within the last day). The obj_list variable gets populated and is passed to the paginator and everything works as expected. I get a certain number of pages and can navigate through pages. Now lets assume we are on the home page again and I select "all time" from the drop down menu. This will trigger the onchange callback and it will call the FilterCategories() function. Note the url in AJAX is "" (an empty string, so pointing to my index page). According to urls.py, it will call my entry_index() view. Because request is ajax, the template used will change (page_template becomes the new template, page_template = entry_index_page.html). Because the new time range specified with the drop down menu and passed on with ajax, I get a new obj_list which is then paginated and produces "objects" which are then passed as context onto the template. Up until this point everything works as expected. I get right amount of pages etc. However, the problem starts when I try to go to the next page with the newly selected filter. When I click the next page button, the request that is being made is not an ajax request so everything that is in the request.is_ajax() conditional is not executed. So in another words a click to the next page is calling my entry_index view again and the template being used this time around is entry_index.html and my filter is reset back to the default, which is the "last 24 hours" filter. Therefore, when I click the next page what I end up getting is actually the default home page again instead of getting the next page of objects with my newly selected drop down filter.
My question is, is there an easy way to fix this so that I can scroll through the pages of my filtered model? Or should I completely abandon this approach and there is an easier way to do this? I apologize for a long post and I hope someone out there will be able to help me out. Thank you for taking your time to read this.
Here's an example of an approach I've taken to having dynamic content displayed on a page using Django and Ajax:
I was tooling a little browser Sci-fi game just to practice this specific technique. Everything took place in a single view:
class GameViewport(TemplateView):
template_name = "game_viewport.html"
#cached_property
def slug(self):
return self.kwargs['slug']
#cached_property
def game(self):
return Game.objects.get(url=self.kwargs['slug'])
#cached_property
def player(self):
return Player.objects.get(game=self.game)
#cached_property
def current_planet(self):
return self.player.current_planet
#cached_property
def left_column(self):
player = self.player
if player.current_location:
node = player.current_node
if len(Location.objects.filter(node=node)) == 0:
spawn_locations(node)
locations = Location.objects.filter(node=node)
else:
locations = Location.objects.filter(planet=node)
html = "Other Sites in ".format(str(node))
for location in locations:
html += '<li>{} ({})</li>'.format(location.name, location.type.name)
return html
elif player.current_node:
planet = player.current_planet
if len(Node.objects.filter(planet=planet)) == 0:
spawn_nodes(planet, get_name_choices())
nodes = Node.objects.filter(planet=planet)
else:
nodes = Node.objects.filter(planet=planet)
html = '<h4><b>Other Starports on {}:</b></h4>'.format(planet.name)
for node in nodes:
html += '<li> {} ({})</li>'.format(node.name, node.type.name)
return html
elif player.current_planet:
system = player.current_system
html = '<h4><b>Known Planets in {}:</b></h4>'.format(system.name)
for known_planet in player.known_planets.filter(solar_system=system):
html += '<li> {} ({})</li>'.format(
known_planet.name,
known_planet.classification.name
)
return html
else:
html = '<h4><bShip Status</b></h4>'
html += '<p><b>Fuel:</b> 100%</p>'
return html
So as you can see, the left column would generate different html data based on what the player's current settings are. This would be plugged into the template like so:
<div class="col-md-3">
<div class="leftColumn">
{% autoescape off %}
{{ view.left_column }}
{% endautoescape %}
</div>
</div>
If the user clicked on a new location, I would send her decision through AJAX:
$(".planetChoice").click(function(){
event.preventDefault();
var submission_data = {planet: $(this).text()};
console.log(submission_data);
$.ajax({
url: $('#visitPlanet').attr('href'),
type: 'GET',
dataType: "json",
data: submission_data,
success: function(html_data) {
window.location.reload();
},
failure: function(data) {
alert('Something went wrong. Please refresh the page.');
}
});
});
All this would do is update the player's state and reload the page according to her new settings:
def visit_planet(request, slug):
player = Game.objects.get(url=slug).player_1
planet = Planet.objects.get(name=request.GET.get('planet', "").strip())
if planet:
player.current_location = None
player.current_node = None
player.current_planet = planet
player.save()
response = {'status': 1, 'message': "Ok"}
return JsonResponse(response)
Thus displaying the new data, as determined by the left_column property.
I went about this by changing the state in the database, but it could just as easily be accomplished with session variables. I found it to be a relatively clean and DRY way of cycling dynamic content. It also has the advantage of giving Django an opportunity to generate or modify data in between clicks.
Not sure if this applies to your situation, but hopefully it sparks an idea!
EDIT: You don't even necessarily need to output HTML. Here's an approach I am using in a different application:
<!--Product Tile #1-->
{% if view.tile_data.0 %}
<div class="col-md-4">
<div class="card hoverable">
<!--Card content-->
<div class="card-block" id="tile_{{ view.tile_data.0.invoice }}_id">
<!--Title-->
<h4 class="card-title">Shipment {{ view.tile_data.0.invoice }}</h4>
<!--Text-->
<p class="card-text">{{ view.tile_data.0.supplier.name }}
<br>
<b>{{ view.tile_data.0.lbs|floatformat }} Lbs # {{ view.tile_data.0.price }} USD</b>
<br>
{{ view.tile_data.0.variety.commodity }} {{ view.tile_data.0.variety }} {{ view.tile_data.0.inshell|shell_display }}</p>
</div>
<!--/.Card content-->
</div>
</div>
{% endif %}
<!--./Product Tile #1-->
This data is directly fed through the view from a model manager:
def tile_data(self, status, first, last):
return self.model.objects.filter(status=status)[first:last]
i am trying to add a search bar on my listview page. it will get all the post items first time, and if a query put in search box, and submitted, it will return a filtered queryset. it renders fine, but only has problem with pagination. for non-filtered queryset, the next page will get the next two posts without any problem, but for filtered queryset, i can see the queryset is correctly reflected by see less pages, but the next page gets me the second page of non-filtered queryset not the filtered queryset. Can anyone give me some pointers on what i am doing wrong here. Thanks
My template looks like this:
{% block content %}
.....
<form action="" method="get">
<input type="text" name='q'>
<input type="submit" value="Search">
</form>
{% for post in object_list %}
....
{% endfor %}
{% if is_paginated %}
<div class="pagination">
<span class="page-links">
{% if page_obj.has_previous %}
<<
{% endif %}
<span class="page-current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}
</span>
{% if page_obj.has_next %}
>>
{% endif %}
</span>
</div>
{% endif %}
I have a listview like below.
class Postlist(ListView):
model=post
paginate_by = 2
query_string = ''
def get_queryset(self):
if ('q' in self.request.GET) and self.request.GET['q'].strip():
query_string = self.request.GET['q']
entry_query = get_query(query_string, ['title', 'body',]) ## call get_query() function
queryset = post.objects.filter(entry_query).order_by('-created')
else:
queryset=post.objects.all().order_by('-created')
return queryset
def get_context_data(self):
context = super(ListView, self).get_context_data(**kwargs)
context['q'] = query_string
## do sth here to pre-populate the input text box
return context
Let me close this. Two options: using hidden field to save the user search terms, and get this to filter off queryset on each request; or using session. Here is the session code sample. The only drawback i could think of using session cache is it caches a whole queryset in memory, so it will kill the memory for high traffic website. Since i am using it for personal website, it doesnt hurt at all.
View file
class Postlist(ListView):
model=post
paginate_by = 2
def get_queryset(self):
query_string = ''
if ('search' in self.request.GET) and self.request.GET['search'].strip():
query_string = self.request.GET['search']
entry_query = get_query(query_string, ['title', 'body',]) ## call get_query to clean search terms
queryset = post.objects.filter(entry_query).order_by('-created')
self.request.session['searchset']=queryset
else:
if self.request.session.get('searchset') and ('page' in self.request.GET):
queryset=self.request.session['searchset']
else:
queryset=post.objects.all().order_by('-created')
if self.request.session.get('searchset'):
del self.request.session['searchset']
return queryset
form file
from django import forms
class SearchForm(forms.Form):
search = forms.CharField(max_length=30)