Queryset in view or in template - python

I am trying to speed up my code. In development, everything ran very smooth, but once I put it in production, and started adding more depth of data into the database, I realize that it is running very slow.
I noticed on django-toolbar that it is running THOUSANDS of queries, where it should only be maybe 10-20. I am wondering if it may be because of the way I have a lot of content being delivered.
For example, I have code that looks like this:
{% if user.profile.is_admin %}
...
{% endif %}
and
{% for stuff in user.profile.get_somestuff %}
...
{{ stuff.info }}
{{ stuff.other_info }}
...
{% endfor %}
Does each one of these execute a new query?
Should I run the query for get_somestuff in the view, pass it through context? I am asking from a performance perspective.

If profile.get_somestuff is an expensive operation and you call it multiple times in the template, and yes, you should call that in the view once and pass the result to the template via context.
def view(request):
...
stuff = request.user.profile.get_somestuff()
return render(request, 'page.html', {'stuff': stuff})
Alternatively, you can use {% with %} tag to create a scope containing the value in its own context:
{% with stuff=user.profile.get_somestuff %}
...
{{ stuff.info }}
{{ stuff.other_info }}
... do some other things with stuff
{% endwith %}
Personally, I would go with the first option because, with the help of django.db.connection.queries, it is relatively easier to monitor db queries you make in the view. Make sure you avoid sending template querysets, lazy expressions etc. as much as possible.
BTW, please note that DEBUG must be set to True for connection.queries to work.

If stuff.info or stuff.other_info are foreign keys to other models then yes, each time you hit each of those for a new stuff obj you could be doing another select query for each one.
select_related might help you here. It'll effectively join the relevant tables on the fk fields you specify in the sql query upfront. The sql query will be more complex than the queries you're running now but far less numerous.

Related

Time SQL Queries in Django

Is there a way to time sql queries in Django?
I know there's such thing in dj debug toolbar but I just need to display time on my web-page.
Since I can get a number of queries with:
len(connection.queries)
Maybe there's a similar way to get the time?
You can show them in templates if you have django.template.context_processors.debug available in your template settings.
It attaches sql_queries list to template.
{% for query in sql_queries %}
{{ query.time }}
{% endfor %}
Make sure that DEBUG is True in your settings and request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS
Of course if you need something more this might help you.

django - filtering objects across multiple templates?

I'm trying to filter objects across two templates. One (the parent) should display the five most recently updated, and the other should display all of them.
I have the latter working perfectly with the following code:
views.py:
...
class ChannelProjectList(generic.ListView):
context_object_name = 'projects_by_channel'
template_name = 'channels/projects_by_channel.html'
def get_queryset(self):
self.channel = get_object_or_404(Channel, slug=self.kwargs['slug'])
return Project.objects.filter(channel=self.channel)
...
HTML:
{% for project in projects_by_channel %}
{{project.name}}
{% endfor %}
But when I go to "include" it on the parent page it breaks. After some research I understand why that is happening and why that isnt the proper way to do it. I dug around and found this, which seems to be exactly what I'm trying to do but when I implemented it, not only did it not work it but also broke the page that is working.
This feels like a pretty simple thing, but since this is my first project I'm running into new things every day and this is one of them.
Final Solution:
With the help of this I realised I needed to copy in the same get_queryset into the second template view, which I was then able to call into the template using "view.channel_projects"
You have two possibilities. First you could define two context variables (like its done in your linked solution) or you could slice the qs in the template.
1. Option slice:
This one would display all:
{% for project in projects_by_channel %}
{{project.name}}
{% endfor %}
This on only displays 5 entries:
{% for project in projects_by_channel|slice:":5" %}
{{project.name}}
{% endfor %}
2. Option define two query sets:
(views.py)
def get_queryset(self):
self.channel = get_object_or_404(Channel, slug=self.kwargs['slug'])
self.channel2 = get_object_or_404(Channel, id=12)#whatever
context["list"] = Project.objects.filter(channel=self.channel)
context["list2"] = Project.objects.filter(channel=self.channel2)[0:5] #this slices the query set for the first entries. If you want to order them first(by date or whatever) use "order_by()"
return context
(html)
{% for project in list %}
{{project.name}}
{% endfor %}
{% for project in list2 %}
{{project.name}}
{% endfor %}
If you want to display a single qs but one time the whole thing and in another template just the first 5 you are better suited with using the slice argument in the template. It keeps the view clean and simple and you don't have to query two times.
I hope that helps if not leave a comment.

Flask - SubViews

I am looking to use a certain design pattern in my application, but I am not sure if my pattern really even fits with Flask mechanisms. I am just verifying that I have not overlooked existing solutions.
I would like to have a top-level View that renders the response of another proxied request. The thing is, I am not proxying external URLs, but rather views from within my same application (kind of like Blueprints that depend on other Blueprints). Similar to the 'render_template()' function, I am looking for something like render_view, or even better, *request_view_as_string*. I then need to process the response and re-render.
I am using template inheritance to the best of my abilities (jinja2), but much of my difficulty is coming from lots of non-template processing in between the template blocks. I am still getting a feel for jinja, and my templates are starting to feel polluted with hacks.
Edit
Basically, I misunderstood the role of jinja. My application needs to build heavier on jinja. I kept trying to get in and out of jinja as quickly as possible, and that is where my nested dependencies were starting to cause problems. Ultimately, most of the features I needed for my "subviews" was built right into Jinja, I just wasn't sure how to properly integrate them with FLask.
First off, Jinja2 supports macros, which let you share functionality between templates:
{# helpers.jinja #}
{% macro generate_select(itrbl) %}
<select{{kwargs|xmlattrs}}>
{% for item in itrbl %}
<option value="{{item.value}}">{{item.text}}</option>
{% endfor %}
</select>
{% endmacro %}
{# page1.jinja #}
{% import "helpers.jinja" as helpers %}
{{ helpers.generate_select(data, name="my_data_field") }}
For more complicated bits of functionality (A / B testing, loading different features depending on what the user's account has enabled, etc.) extends, include, and import can take variable values:
{# A custom template with a *lot* of hooks #}
{% extends base_template %}
{% import custom_functionality_provider as provider %}
{% block common_name %}
{% if features.feature_x %}
{% include feature_x_include %}
{% endif %}
{{ provider.operation() }}
{% endblock common_name %}
#app.route("/some-route")
def some_route():
# Of course, in real life you would determine these values
# on the basis of user / condition lookups, rather than
# hardcoding values in your render_template call
render_template("custom.jinja", base_template="AB/A/base.jinja",
custom_functionality_provider="macros/lowcostplan.jinja",
feature_x_include="AB/A/features/feature_x.jinja",
features=some_features_object)
Finally, you can pass callables that return strings to any Jinja template, giving you access to the full power of Python:
def custom_implimentation_a(**context_args):
return render_template("template_a.jinja", **context_args)
def custom_implimentation_b(**context_args):
return render_template("template_b.jinja", **context_args)
#app.route("/some-route")
def some_route():
if condition:
provider = custom_implimentation_a # Note, no parenthesis
else:
provider = custom_implimentation_b
return render_template("some_page.jinja", provider=provider)
I do consider Sean's first answer as the most appropriate, but I did run across this little mechanism for those times when Jinja is making Python tasks a bit difficult.
http://werkzeug.pocoo.org/docs/local/
This should be a little more productive than Flask's g variable. See also a slightly different usage (when one global 'namespace' is no longer manageable)
http://flask.pocoo.org/snippets/13/
I very often forget that Flask and Werkzeug are related projects. The huge benefit of this is that much of their functionality does not overlap with the other project.
When you are newbie approaching from the Flask side, if you feel like Flask is missing a few gears, there is a good chance its because they already included them in Werkzeug.

Django template check for empty when I have an if inside a for

I have the following code in my template:
{% for req in user.requests_made_set.all %}
{% if not req.is_published %}
{{ req }}
{% endif %}
{% empty %}
No requests
{% endfor %}
If there are some requests but none has the is_published = True then how could I output a message (like "No requests") ?? I'd only like to use Django templates and not do it in my view!
Thanks
Even if this might be possible to achieve in the template, I (and probably many other people) would advise against it. To achieve this, you basically need to find out whether there are any objects in the database matching some criteria. That is certainly not something that belongs into a template.
Templates are intended to be used to define how stuff is displayed. The task you're solving is determining what stuff to display. This definitely belongs in a view and not a template.
If you want to avoid placing it in a view just because you want the information to appear on each page, regardless of the view, consider using a context processor which would add the required information to your template context automatically, or writing a template tag that would solve this for you.

Sorting and indexing into a list in a Django template?

How can you perform complex sorting on an object before passing it to the template? For example, here is my view:
#login_required
def overview(request):
physicians = PhysicianGroup.objects.get(pk=physician_group).physicians
for physician in physicians.all():
physician.service_patients.order_by('bed__room__unit', 'bed__room__order', 'bed__order')
return render_to_response('hospitalists/overview.html', RequestContext(request, {'physicians': physicians,}))
The physicians object is not ordered correctly in the template. Why not?
Additionally, how do you index into a list inside the template? For example, (this doesn't work):
{% for note_type in note_types %}
<div><h3>{{ note_type }}</h3>
{% for notes in note_sets.index(parent.forloop.counter0) %}
#only want to display the notes of this note_type!
{% for note in notes %}
<p>{{ note }}</p>
{% endfor %}
{% endfor %}
</div>
{% endfor %}
Thanks a bunch, Pete
As others have indicated, both of your problems are best solved outside the template -- either in the models, or in the view. One strategy would be to add helper methods to the relevant classes.
Getting a sorted list of a physician's patients:
class Physician(Model):
...
def sorted_patients(self):
return self.patients.order_by('bed__room__unit',
'bed__room__order',
'bed__order')
And in the template, use physician.sorted_patients rather than physician.patients.
For the "display the notes of this note_type", it sounds like you might want a notes method for the note_type class. From your description I'm not sure if this is a model class or not, but the principle is the same:
class NoteType:
...
def notes(self):
return <calculate note set>
And then the template:
{% for note_type in note_types %}
<div><h3>{{ note_type }}</h3></div>
{% for note in note_type.notes %}
<p>{{ note }}</p>
{% endfor %}
</div>
{% endfor %}
"I'd like to do this from within a template:"
Don't. Do it in the view function where it belongs.
Since the question is incomplete, it's impossible to guess at the data model and provide the exact solution.
results= physician.patients.order_by('bed__room__unit', 'bed__room__order', 'bed__order')
Should be sufficient. Provide results to the template for rendering. It's in the proper order.
If this isn't sorting properly (perhaps because of some model subtletly) then you always have this kind of alternative.
def by_unit_room_bed( patient ):
return patient.bed.room.unit, patient.bed.room.order, patient.bed.order
patient_list = list( physician.patients )
patient_list.sort( key=by_unit_room_bed )
Provide patient_list to the template for rendering. It's in the proper order.
"how do you index into a list inside the template"
I'm not sure what you're trying to do, but most of the time, the answer is "Don't". Do it in the view function.
The template just iterate through simple lists filling in simple HTML templates.
If it seems too complex for a template, it is. Keep the template simple -- it's only presentation. The processing goes in the view function
You should be able to construct the ordered query set in your view and pass it to your template:
def myview(request):
patients = Physician.patients.order_by('bed__room__unit',
'bed__room__order',
'bed__order')
return render_to_response('some_template.html',
dict(patients=patients),
mimetype='text/html')
Your template can then loop over patients which will contain the ordered results. Does this not work for you?
EDIT: For indexing, just use the dot syntax: mylist.3 in a template becomes mylist[3] in python. See http://docs.djangoproject.com/en/dev/ref/templates/api/#rendering-a-context for more information.
This is one way of doing it, although very ugly :
{% for note in note_sets|slice:"forloop.counter0"|first %}

Categories

Resources