Alright, I have a Django view, like this:
#render_to('home/main.html')
def login(request):
# also tried Client.objects.select_related().all()
clients = Client.objects.all()
return {'clients':clients}
And I have a template, main.html, like this:
<ul>
{% for client in clients %}
<li>{{ client.full_name }}</li>
<ul>
{% for pet in client.pets.all %}
<li>{{ pet.full_name }}</li>
{% endfor %}
</ul>
{% endfor %}
</ul>
I also print out all the queries in sql_queries at the bottom of my base template. When I run this view, the following queries are made:
SELECT `home_client`.`id`, ... FROM `home_client`;
SELECT `home_pet`.`id`, ... FROM `home_pet` WHERE `home_pet`.`client_id` = 1;
SELECT `home_client`.`id`, ... FROM `home_client` WHERE `home_client`.`id` = 1;
SELECT `home_client`.`id`, ... FROM `home_client` WHERE `home_client`.`id` = 1;
SELECT `home_pet`.`id`, ... FROM `home_pet` WHERE `home_pet`.`client_id` = 2;
SELECT `home_client`.`id`, ... FROM `home_client` WHERE `home_client`.`id` = 2;
My question is, why are all these queries being made? Shouldn't it just be 1 query to retrieve all the clients and a query per client to retrieve all the pets from each client? I have 2 clients in the home_client table, so it should be 3 queries total. Most troubling of all is that queries 3 and 4 are 100% identical. I don't want to "prematurely optimize" or anything but I do want to make sure Django isn't being wildly inefficient. Any help on this would be appreciated. Thanks.
Django uses a cache. The RDBMS uses a cache. Don't prematurely optimize the queries.
You can play with bulk queries in your view function instead of one-at-a-time queries in your template.
#render_to('home/main.html')
def login(request):
# Query all clients
clients = Client.objects.all()
# Assemble an in-memory table of pets
pets = collections.defaultdict(list)
for p in Pet.objects.all():
pets[pet.client].append(p)
# Create clients and pets tuples
clientsPetTuples = [ (c,pets[c]) for c in clients ]
return {'clientPets': clientsPetTuples}
However, you don't seem to have any evidence that your template is the slowest part of your application.
Further, this trades off giant memory use against SQL use. Until you have measurements that prove that your template queries are actually slow, you shouldn't be over thinking the SQL.
Don't worry about the SQL until you have evidence.
try using Client.objects.all().select_related()
This will automagically also cache related models in a single database query.
Does Client 1 have 2 Pets and Client 2 have 1 Pet?
If so, that would indicate to me that Pet.full_name or something else you're doing in the Pet display loop is trying to access its related Client's details. Django's ORM doesn't use an identity map, so accessing the Client foreign key from any of your Pet objects would require hitting the database again to retrieve that Client.
P.S. select_related won't have any effect on the data you're using in this scenario as it only follows foreign-key relationships, but the pet-to-client relationship is many-to-one.
Update: if you want to avoid having to change the logic in Pet.full_name or having to perform said logic in the template instead for this case, you could alter the way you get a handle on each Client's Pets in order to prefill the ForeignKey cache with for each Pet with its Client:
class Client(models.Model):
# ...
def get_pets(self):
for pet in self.pets.all():
setattr(pet, '_client_cache', self)
yield pet
...where the 'client' part of '_client_cache' is whatever attribute name is used in the Pet class for the ForeignKey to the Pet's Client. This takes advantage of the way Django implements access to ForeignKey-related objects using its SingleRelatedObjectDescriptor class, which looks for this cache attribute before querying the database.
Resulting template usage:
{% for pet in client.get_pets %}
...
{% endfor %}
Related
I was wondering if there is a way to make this more optimised.
class AppTopic(models.Model):
topic = models.CharField(max_length=20) # lowercase (cookies)
class UserTopic(models.Model):
topic = models.CharField(max_length=20) # Any case (cOoKiEs)
app_topic = models.ForeignKey(AppTopic) # related to (cookies -> lowercase version of cOoKiEs)
class User(models.Model):
topics = models.ManyToManyField(UserTopic) # AppTopic stored with any case
The goal is to have all AppTopics be lowercase on the lowest level, but I want to allow users to chose what capitalisation they want. In doing so I still want to keep the relation with it's lowercase version. The topic on the lowest level could be cookies, the user might pick cOoKiEs which should still be related to the orignal cookies.
My current solution works, but requires an entirely new table with almost no use. I will continue using this if there isn't really a smarter way to do it.
There's nothing in the Django model API that would allow you to manipulate values from the models themselves. If you don't want to change the value in the database or in the model instance, you can change how it displays on the template level using the
lower filter in Django template language.
<body>
<div>
{% if condition %}
<h1>{{AppTopic|lower}}</h1>
{% else %}
<h1>{{AppTopic|??}}</h1> #AppTopic but camelcase. There's no camelcase filter in Django
{% endif %}
</div>
</body
Views.py
def View(request, condition)
...
return render(request, 'template.html', {condition:'condition'})
What I want to do?
I have an app have three models:Series,Section and Episode,every one have a one-many query(by ForeignKey). just like this
series-> many Section,section-> many Episode
Now I will show a section with episodes information in series page, but it make more query.
now code
views.py
series = Series.objects.get(id=series_id)
section = Section.objects.filter(series=series)
list.html
{% for item in sections %}
...
{% for episode in item.episode_set.all %}
...
{% endfor %}
...
{%endfor%}
models.py
class Section(models.Model):
series = models.ForeignKey(Series)
....
class Episode(models.Model):
section = models.ForeignKey(Section)
What I want to get ?
an example code tell me how to query in views.py and use just little query.
you can guess, in my code, if here are many section and many episode, it will have many query.
Some idea.
I use Laravel Before, In Laravel , it has a hasMany Function, I can use it to get other models items(Define by belongsTo).
Is Django has same function?
If in template you need only episodes, you can query just them with single query
Episode.objects.filter(section__series=series_id)
But if you need all data then you can use prefetch_related Django docs.
The simplest example looks enough for your code
series = Series.objects.filter(id=series_id).prefetch_related('section_set', 'section_set__episode_set').get()
After this calls to series.section_set.all() and to section.episode_set.all() will not produce extra query.
I have Django app, which have following statements:
response = render_to_response('template.html', {'s':s, 'r':r}, context_instance=RequestContext(request))
The typical statement at template.html is:
<tbody>{%for m in r.m_set.all %}<tr>
<td>{{m.id}}</td>
<td>{{m.Name}}</td>
<td>{{m.MaterialLot.id}}</td>
<td>{{m.MaterialSublot.id}}</td>
<td>{{m.Description|truncatechars:20}}</td>
<td>{{m.StorageLocation.id}} - {{m.StorageLocation.Name}}</td>
<td>{{m.Quantity|floatformat:"-3"}}</td>
<td>{{m.QuantityUnitOfMeasure.id}}</td>
<td>{{m.Status.id}}</td></tr> {%endfor%}</tbody>
There are about 10 thousands records. the page response time take about 3 minutes(ThinkServer, Linux, Apache, mod_wsgi, Python3.4, Django 1.9.4, MySQL), is this normal?
Thanks!
Every call to {{ m.XXX.id }} leads to separate SQL-query for the XXX instance. To avoid this you should use the select_related() method of the queryset.
Add the following method to the class of the r variable:
def get_all_m(self):
return self.m_set.all().select_related()
and then use it in the template:
{% for m in r.get_all_m %}
To only access the id of the related models, add the _id suffix to the field name. This data is already available because that's the value of the foreign key, so you don't need extra queries or joins. However, you are accessing the Name property of the StorageLocation field, so you need a join to prevent doing a query in every iteration.
Your call for the data becomes:
r.m_set.select_related('StorageLocation').all()
Your template becomes:
<tbody>
{%for m in r.m_set.all %}
<tr>
<td>{{m.id}}</td>
<td>{{m.Name}}</td>
<td>{{m.MaterialLot_id}}</td>
<td>{{m.MaterialSublot_id}}</td>
<td>{{m.Description|truncatechars:20}}</td>
<td>{{m.StorageLocation.id}} - {{m.StorageLocation.Name}}</td>
<td>{{m.Quantity|floatformat:"-3"}}</td>
<td>{{m.QuantityUnitOfMeasure_id}}</td>
<td>{{m.Status_id}}</td>
</tr>
{%endfor%}
</tbody>
Just remember that if you need access to a field other than id on a related model, add the field name to the select_related() call.
I want to create a custom model with methods that connect to an existing DB and return data based on custom queries injected into Django. I am obviously having some problems with this, and am wondering if this is possible with my current approach. I feel like this is either a trivial question or I am misunderstanding something fundamental here. Here is my code so far:
from django.db import models
import datetime
from django.utils import timezone
class data_model(models.Field):
description = "return and create data objects for visulaizations"
def __init__(self, days, action):
self.days = days
self.action = action
if(self.action == ""):
self.action = "inspections"
getVioPoints(self.action)
def getVioPoints(self):
#get points query here and get data from db
return self
Within getVioPoints, I want to create a query string - like what you would see in a PHP $query = "select tuples where what I want = something" type of situation. Then return the data in a way that my template views can access it like so:
<ul>
{% for choice in data_returned %}
<li> {% choice.title %} </li>
{% endfor %}
</ul>
Any ideas? Any assistance would be greatly appreciated.
Thanks.
You can make custom query and put result into json.
You can read about custom queries here:https://docs.djangoproject.com/en/dev/topics/db/sql/#executing-custom-sql-directly,
but this isn`t django-way - you just ignore orm layer and have to write all sql queries by yourself, I recommend you to create model, connect it to db and make queries through orm.
I'm a little rusty with django.
I'm wondering if anyone can tell me how I count the db objects from this query:
UserEnteredTld = Tld.objects.filter(FKtoClient=request.user, auth=0)
I used to do:
UserEnteredTld = Tld.objects.filter(FKtoClient=request.user, auth=0).count()
In the template (with the var):
{% if UserEnteredTld %}
<h3>I have Tld's</h3>
{% endif %}
the view:
UserEnteredTld = Tld.objects.filter(FKtoClient=request.user, auth=0).count()
UserAuthTld = Tld.objects.filter(FKtoClient=request.user,auth=1).count()
return render(request, 'accounthome.html', {
'UserEnteredTld':UserEnteredTld,
'UserAuthTld':UserAuthTld
})
model
class Tld(models.Model):
auth = models.BooleanField(default=False)
FKtoClient = models.ForeignKey(User)
but, this appears to not be outputting anything. (I verified actual rows exist...)
To be clear: I'm simply trying to count the number of rows for the Tld table where a ForeignKey exists for the logged in user and the auth=0.
Don't use count for that. Use exists (docs).
user_entered_tld = Tld.objects.filter(FKtoClient=request.user, auth=False).exists()
{% if user_entered_tld %}
<h3>I have Tld's</h3>
{% endif %}
Some notes:
Django latest version is 1.7 (on beta). It's impossible you're using 2.6.2 (that seems like a Python version)
Don't camel-case your variables. Use user_entered_tld instead of
UserEnteredTld. It's a good Python convention.