i'm having a performance issue while rendering a django template with a prefetch queryset witch is not really large (~1000 objects in production environment / ~200 objects in developement environment) but has several level of nesting.
Here is the prefetch :
stories = Story.objects.select_related(
'commande',
'commande__societe',
'commande__plateforme',
'client',).prefetch_related(
Prefetch('crm_message_related',
queryset=Message.objects.select_related(
'societe',
'plateforme',
'type_message').order_by('-date_received')),
Prefetch('commande__crm_feedback_related'),
Prefetch('commande__crm_guarantee_related'),
Prefetch('commande__soyouz_item_related',
queryset=Item.objects.select_related(
'etat', 'produit', 'produit__produit_enhanced', )),
Prefetch('commande__tagged_items__tag'),
Prefetch('commande__soyouz_item_related__tagged_items__tag'),
Prefetch('commande__soyouz_item_related__soyouz_annulationclient_related'),
Prefetch('commande__soyouz_item_related__soyouz_achat_related'),
Prefetch('commande__soyouz_item_related__soyouz_achat_related__soyouz_receptionachat_related'),
Prefetch('commande__soyouz_item_related__soyouz_achat_related__soyouz_annulationachat_related'),
Prefetch('soyouz_action_related'),
Prefetch('soyouz_action_related__receptionmessage__message',
to_attr='receptionmessages',
queryset=Message.objects.order_by(
'-date_received').select_related(
'societe', 'type_message', 'plateforme'))
).order_by(
'-commande__date_commande',
'-date_created'
).all().distinct()
The SQL run smoothly, thats not the issue.
The issue is when i try to render my template witch is basicaly
{% for story in stories %}
{% with items=story.commande.soyouz_item_related.all %}
{% for item in items %}
{% for tag in item.tagged_items.all %}
<button>{{ tag.tag }}</button>
{% endfor %}
{{ item.titre|safe|truncatechars:50 }}
{% endfor %}
{% endfor %}
It takes about 10 sec to display the page in production environment.
I profiled it in my development environment with django-template-timing (https://github.com/orf/django-debug-toolbar-template-timings) and indeed:
name Times Tot Time Queries Queries Time
stories.html 1 2814,1 ms 0 0 ms
3 seconds for 3 loops with 200 data (in development environment) ? It seems a lot.
Any ideas to improve the speed of template rendering ?
Thanks a lot!
Although django-template-timing reports the rendering time to be 2.8s, I suspect most of the time is consumed in executing the complex SQL query.
In Django, QuerySets are evaluated lazily. This means, the statement you posted Story.objects.select_related(...).distinct() does NOT execute the query in database. The SQL gets executed later. Since you didn't post all the code before rendering the template, I am not sure if the QuerySet gets evalueted before rendering. If not, it may be executed when iterating stories in the template:
{% for story in stories %}
If this is the case, then maybe improving your SQL can reduce the time.
You can check if SQL execution is the culprit by inserting this before rendering the template:
stories = [story for story in stories]
This iteration gets the SQL executed before rendering. After this, if django-template-timing reports a much shorter rendering time, you know SQL is the problem.
If it is indeed a template-rendering performance issue, there are some alternatives:
Use a more performant template engine, like Jinja2.
Chances are there is room for improving rendering performance with Django template: https://stackoverflow.com/a/26592207/954376.
Use a custom tag and generate the output outside the template. That will help avoid the django template overhead.
Related
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?
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.
I have problem with one idea (dynamic sort template in django)
Now I have simply solution for sorting my data but it is not so good because I have couple of buttons which adnotate to sorting view and in this way I have sorted list of my data.
I tried to use angularjs, I think this is the best way to do it but I have problem too. For example:
<div ng-app="" ng-init="sort_by = 'updated_at'">
<button ng-click="sort_by = 'id'">id</button>
<button ng-click="sort_by = 'created_at'">created_at</button>
<button ng-click="sort_by = 'issuer'">issuer</button>
<button ng-click="sort_by = 'handler'">handler</button>
<p>{% verbatim angular %} {{sort_by}} {% endverbatim angular %}</p>
{% for fault in faults|dictsort:{{sort_by}} %}
in theory it can works. but not.
I try in this way and in apostrophe and I try with another block like above {% verbatim angular %} and this is not working giving me an error like this:
'for' statements should use the format 'for x in y': for fault in faults|dictsort:'{% verbatim angular
so it is even not recognizing angular block.
I have to ask You for help and it doesn't have to be angular, if it is better idea to do this in template or maybe stricte django way??
Thanks for help me :)
Why you type ng-app="" ? You should put here name of your AngularJS application. Did You create your AngularJS module first?
You can sort both in frontend and backend, but You should do this in frontend - it is the job of web browser - backend should be responsible only for generating data to be consumed for frontend.
Something like this {% for fault in faults|dictsort:{{sort_by}} %} can't work. You try to define an AngularJS variable called sort_by, and then use it in Django filter. Django doesn't know nothing about that variable.
Both Django and AngularJS use {{}} for variable bindings in templates. You can change these symbols for AngularJS or use verbatim and endverbatim tag in Django.
I have a homepage, which I want to display a login form when user is not logged in or display a list of items belong to that user if he/she already logged in.
So far I came up with 2 methods:
Check whether user is authenticated in views.py and render corresponding view (in my views.py):
if request.user.is_authenticated():
return render(request, 'items.html')
else
return render(request, 'login.html')
Check directly in template and generate corresponding HTML for each case (in my index.html):
{% if user.is_authenticated %}
HTML for my items list
{% else %}
HTML for my login form
{% endif %}
Question
So which method is better for handling this? Are those methods differ much in performance? Is there any standard that we should handling these in views.py or in template itself?
I don't think there is a big performance difference. What's most important is how much you should stick to MVC pattern.
A template is meant to just display some sort of data that the view provides. Any kind of logic like deciding what kind of data to show based on requester's state should always be implemented by the view. Thus, you should move your logic into view function for the cleanness of your design.
TL;DR
Logic should be in your python code, not your template as much as possible. Due to maintenance and future-proof reasons.
Elaborate
Code quality: you can test your business logic when it's in your python not when it's in templates. The former improve your code quality and your value as a developer ;
Future-proof: you don't know which technology your application is going to use in the future, so avoiding tech-mingling will help you when upgrading it (you will be able to upgrade at different pace).
Separation of concerns principles: do you want a code that is a spaghetti plate, where you can't refactor a thing without impacting ten others?
Code legacy: you don't know who is going to work on your code neither which code you're going to work on. Don't make it hard for them (it would probably be your future self) ;
Clean code: that express itself in a single dialect is always better that mixing languages ;
Knowledge scope: front-end is often the responsibility of people with low programming skills (HTML/CSS are declarative) and you don't want them to mess with your business logic.
It depends on your html. If you want to change only a little part of your code based on the condition, check inside a template:
{% if user.is_authenticated %}
<h3>Welcome</h3>
{% else %}
Login
{% endif %}
But if items.html and login.html are different and big templates, you should definitely do the login inside your view.
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.