Django paging with slicing - python

I'm new to Django and Python and I'm trying to understand how to accomplish paging without getting all the records from a QuerySet first. All the examples I've seen with QuerySets will get all the records first like below.
tickets = Ticket.objects.filter(site=site.id)
paginator = Paginator(tickets, settings.PAGE_SIZE)
This seems to make sense so that the Paginator will have a reference to how many pages it needs. However, this seems inefficient to get all the records for each page request. I know that QuerySets can be sliced to return a range of records.
How do I design my paging in order to only get the records pertinent for that page (slicing?), yet still have paging features?
Edit: Added template code that iterates.
{% for ticket in tickets.object_list %}
{{ ticket }}<br/>
{% endfor %}

Underlying queries for the QuerySet objects are not executed until you explicitly evaluate them. Explicit evaluation occurs whenever you iterate through them, which includes calling str() or unicode().
Thus, the above code snippet is indeed efficient. The line tickets = Ticket.objects.filter(site=site.id) creates a new QuerySet, but the query isn't evaluated yet.
For the same reason, stuff like Model.objects.filter(foo).filter(bar).order_by(baz)... doesn't execute a single SQL query.

Related

Reducing Django queries! Get all results in one query rather than multiple?

In my program, I am getting all items that belong to a table and are part of a certain category. This should be a really simple SQL query...but it seems like Django is making things much more complicated.
sqs = super(ItemView, self).get_queryset()
res = sqs.exclude(item_status='hidden')
return res
There are ~50 items that should be found. In the view, Django gets a queryset that is full of <SearchResult> objects. This gets sent to the front end where it is looped over and added to the page.
{% for item in items %}
{% individual_item %}
{% endfor %}
The Django toolbar is showing an individual query for every single item, so in this case, over 50 queries for what should be one.
Am I just misunderstanding how Django works and this is normal behavior? Or is there a way for me to run this as the one simple query it should be and send all the results from the view to the front end?

Rendering Django Template Blocks in Specific Places on Page

I am trying to achieve something in Django Templating Language without knowing whether it is possible (without resorting to JS or something like that).
I have the following code (from Django-Oscar) which renders 3 blocks of promotions on the main page:
{# Render promotions #}
<div id="promotions">
{% for promotion in promotions_page %}
{% render_promotion promotion %}
{% endfor %}
</div>
These three blocks are Single Item, Products and New Arrivals. The code above appears in the layout.html which is essentially responsible for rendering the entire layout of the main page.
The problem is that as soon as soon as Django encounters this code, it renders all of the promotions there one after another. I, however, would like to chose where on the page I place them. What's more, I do not believe that I have much flexibility in how I render them, read - I do not want to change the Oscar e-commerce and rendering code unless absolutely necessary.
Since I have access to individual templates for Single Item, Products and New Arrivals promotions, I tried creating DTL blocks there and then calling those blocks at proper places on the layout.html. However, that does not work.
What is a proper and most efficient way of achieving what I am trying to do?
Django templating system provides features that let you add your custom templates in place of the ones that come with the apps. You don't need to patch django-oscar for this.
Start here: https://docs.djangoproject.com/fr/1.11/howto/overriding-templates/
Hope I added enlightenment.

Reversing complex Admin URLs from templates

I find myself needing a bit more flexibility than what I understand I can do based on the Django documentation for reversing Admin URLs. I'm doing things like:
{% url admin:billing_creditcardtoken_add %}?customer={{ user.id }}
This works, but it feels like I should be able to do it without leaving the template tags.
If I want to find all CreditCardToken objects from the billing application that belong to the current user, I find myself doing:
{% url admin:billing_creditcardtoken %}?customer={{ user.id }}
...but this fails altogether. Is there a more elegant way of getting these URLs?
I was looking at this the wrong way. While:
{% url admin:billing_creditcardtoken_add %}?customer={{ user.id }}
...might be somewhat ugly, the only thing added syntax would serve to do is try to construct a query string, which isn't something one reverses URLs to do normally anyway. So this is an acceptable method of accomplishing this task.
What I was looking for in the second turned out to be:
{% url admin:billing_creditcardtoken_changelist %}?customer={{ user.id }}
...changelist, as it turns out, does not show a history of changes, but creates a list of possible items to change. Adding the query string applies the proper filter I needed.

How to have partially pre-rendered fields using Django-haystack

I've started using a rendered field in my django-haystack indexing to avoid database hits when a search is rendered. This is working well for the most part, but I have some runtime information (such as an edit button for staff) in the results as well that I'd like to splice in. A simplified example:
{{object.name}}<br/>
{% if user.is_staff %}
Edit
{% endif %}
{{ object.description}}
The user logic obviously can't be applied at indexing time so doesn't occur. Without using javascript hacks is there a way to splice some runtime output in amongst the pre-rendered text? I'm thinking it can be done by passing the rendered text with some formatting placeholders to a custom template tag, but I wonder if there's another way.
Edit: Perhaps multiple rendered, stored fields might be possible, covering the main fragments of the search result surrounding the logic parts, and then assembled at run time in the main results template. Would this work?

How do I pass dissimilar data from view to template?

I am a relatively new to Django, and have just run into a wall, but I am sure this will be a cake walk for you veterans out there. I have a list of items I am displaying in a table in a template. That is no problem I create an object (list of values) in my view send it to the template and render the table. However, I would like to also show on my template a bunch of count()’s displayed as links, that when clicked will further filter the list of items displayed. For example, I may have items in the list that cost between $25 and $50, my link would show that there are say 20 items that match that criteria. When the link is selected in sends a request to the url.py that in turn executes a view that further filters the queryset then renders template again.
How do I get the count() info to the template? I do not think I can send two separate lists (objects) to the template (at least I have not been able to figure out how yet). I think I need to get the counts at the view and then somehow append them to my list object, but I’m not sure how to do that and also, not quite sure how to parse those values in the template. I want the counts to show separate from the table generated from my list object, and I am somewhat concerned I’m going to mess up my table that is working fine now.
I would appreciate any suggestions you have about how to tackle this, and I would really appreciate code examples because I am still somewhat Python/Django code challenged.
You can send as many lists or objects to the template as you like. Template context is just a dictionary, and you can add items to it as necessary.
context = {
'list1': my_first_list,
'list2': my_second_list,
...
}
Your requirements are vague. Code helps. Also. Periods to end sentences help.
I think I need to get the counts at the view and then somehow append them to my list object
how to parse those values in the template.
Here's an approach. It doesn't use aggregate functions. They are more efficient, but also a little more difficult to understand. https://docs.djangoproject.com/en/1.3/topics/db/aggregation/
You have something like this in your view:
object_list = Model.objects.filter( some_attribute=some_value )
You do this in your form to see a count.
{% for obj in object_list %}
<tr><td>{{obj.name}}</td> <td>{{obj.related_set.count}}</td><tr>
{% endfor %}
This evaluates obj.related_set.count() for you. It's not the most efficient (aggregates are more efficient). But it's simple.
If you want a link, you'll replace the simple {{obj.related_set.count}} with something that includes a link
{{obj.related_set.count}}

Categories

Resources