This QuerySet (Let's say Model model has 12 field):
objects = Model.objects.filter(...)
And this template:
{% for object in object %}
<a href='{{ object.get_absolut_url }}'>Foo: {{ object.bar }}</a>
{% endfor %}
perform SQL query which gets unnecessary fields (every 12 fields + relations). I want Django to get only 'bar' field. How can I do this?
By the way I know about values() method, but as it returns dict, I can't call Model methods such as get_absolute_url().
You want to use only():
objects = Model.objects.select_related().only("bar").filter(...)
Keep in mind however if you limit too much of the data down and then use the objects in other ways you can actually cause the ORM to execute extra queries, so make sure to be using something like django-debug-toolbar to ensure you aren't removing these unnecessary fields to only incur the hit of lots of unnecessary queries which is a worse situation.
FYI you can also use defer() to list the fields you don't want loaded if you want to think about it in the other direction.
Related
Rendering a page gets really slow when related objects are requested in a template.
class Item(models.Model):
name = models.CharField(max_length=160)
...
class Box(models.Model):
...
items = models.ForeignKey(Item, on_delete=models.CASCADE, null=True)
#template
{% for item in items %}
{{ item.box_set.first }}
{{ item.box_set.latest }}
{% endfor %}
Debug toolbar shows there many duplicate queries.
Why is this happening? Is there a way to speed this up?
The Django ORM has to make a request to the database when accessing a related field unless it's already cached. The main ways of caching the related objects are via select_related and prefetch_related.
What you're trying to do is a bit more difficult; you're trying to get two specific items from a collection. You can use .annotate() and Subquery to pull singular fields from a related model. This would be useful if you just wanted to display single field from box, but if you need the whole box instance this won't work.
Like you see the codes below, I'm manually using an attribute status in Store model to show my stores in HTML Templates. The problem is the more codes I make, the more repeating codes happen.
I'm trying to find a way to avoid those inefficient repetitions. Is it possible to set up in models.py to show only active stores to be shown in HTML templates?
I'm asking this because I've already done a similar thing to this. I have a string type attribute, but I need it in a list format in my templates, so I made a function to call it only with a list format. But, I can't figure out how to hide inactive stores in the same way.
Can anyone give me some suggestins for this?
models.py
class Store(models.Model):
status = models.CharField(max_length=20,
choices=(
('active', 'Active'), # ('Stored value', 'Label shown on the UI')
('inactive', 'Inactive'),
),
default='inactive')
...
HTML Templates
{% if store.status == 'active' %}
... Show store
{% else %}
... Do not show store
{% endif %}
Usually, though, People need to select only a subset of the complete set of objects. To refine the initial QuerySet, Here are the two most common ways to proceed:
Use filter() or exclude() with your queryset before sending it to the template.
filter(kwargs**)
Returns a new QuerySet containing objects that match the given lookup parameters.
active_stores = Store.objects.filter(status='active')
# send active_stores to template
or
exclude(kwargs**)
Returns a new QuerySet containing objects that do not match the given lookup parameters.
active_stores = Store.objects.exclude(status='inactive')
# send active_stores to template
In your template, you can loop through without a problem of inactive stores
{% for store in active_stores %}
{{ store }}
{% empty %}
No stores
{% endfor %}
See further explanations in the Django Documentation
Do not filter in the template language, filter in Python. From within the view function and/or class, make sure to filter the queryset:
objs = stores_queryset.filter(status='active')
Then work with the filtered objs in the template, and just iterate over objs without a conditional. It's best to keep logic out of templates entirely, always passing in the correctly prepared context data.
Trying to figure out Django... I'd like to build a table in a template that is largely all the data from a Django model. My preference would be to send the model queryset PersonDynamic.objects.all() to the template and have it figure out the column names and then loop through each row, adding the fields for that row. This kind of approach would give me a lot of flexibility because if the model changes the template will automatically change with it.
One approach could be to just move the column headers and each record into lists which I then send to the template but this seems less efficient than just sending the queryset.
What is the best way to do this?
Am I right about efficiency?
Does sending lists rather than model instances come with a larger risk of problems if there are a bazillion records or does that risk exist, regardless of approach?
Thanks!
Try looking at the code for django.contrib.admin, and how the built-in admin site makes tables. The admin site adds a lot of extra features to change how fields are displayed, and what fields to display, but it should give you some idea of how things work.
The absolute simplest way I can think to do what you want is to send the template a list of headers you want to use, and the queryset called with the values_list method. values_list takes a series of field names, and returns another queryset that will yield a tuple of field values instead of a model object. For example, say your PersonDynamic looks like this:
class PersonDynamic(Model):
id = AutoField()
name = CharField()
likes_python = BooleanField()
You could then send something like this to your template:
fields = ['id', 'name', 'likes_python']
qs = PersonDynamic.objects.values_list(*fields)
context = Context({'headers': fields, 'rows': qs})
template.render(context)
And your template could do:
<table>
<tr>{% for item in header %}<th>{{ item }}</th>{% endfor %}</tr>
{% for row in rows %}
<tr>{% for cell in row %}<td>{{ cell }}</td>{% endfor %}</tr>
{% endfor %}
</table>
For your other questions, this will run into problems for larger tables; it takes time and memory to loop over large lists like this, so generally a strategy like pagination is used, where only X items are displayed per page.
Say I have a model:
class Entry(models.Model):
...
tags = TaggableManager()
When I iterate over Entry.objects.all() in a template, entry.tags.all produces one more query to the database. Is it possible to reduce queries number? Using something like select_related() (I know it won't work, since django-taggit uses manytomany relation, but I am sure there should be a way to select all entries with related tags in 1 hit)?
From Django 1.4 onward, you can use prefetch_related to retrieve one-to-many relations on a queryset in a single query. Unfortunately this doesn't work brilliantly with django-taggit, because the 'tags' property is a manager rather than a true relation, and so prefetch_related can't make sense of it. Instead, you need to follow the tagged_items relation:
entries = Entry.objects.prefetch_related('tagged_items__tag')
You then need to go through some similar contortions in the template code to access the prefetched tags, because entry.tags.all will run another query rather than making use of the prefetch:
{% for tagged_item in entry.tagged_items %}
<li>{{ tagged_item.tag.name }}</li>
{% endfor %}
Try using Select Reverse it's designed to grab the entirity of a many2many relationship with a single query.
I'm wrestling with how to best create HTML pages in Django that can either be used for displaying or editing data. That is, I'd like the field's values to appear as text in display mode, but in their widgets when in edit/add mode. It appears that Django wasn't designed to do this: the fields always appear in their widgets (eg, text input, text area,
etc).
Is there a common technique for handling this, short of using forms for one, and not the other?
I was thinking of a custom templatetag filter that could be used for every form field, like:
{{ form.field_name|render_field:mode }}
where render_field would either return the field's HTML widget, or just the value as text, based on the mode.
Have I missed something, or is this a viable solution?
Answering my own question, apparently. I ended up with a three-part solution:
attach the model to the form, so I'll have the default display widgets for each field
write the form using a template tag, passing it the form.field, user, and action
write a render template tag to handle #2
Step one:
form.model = Model(...)
Step two:
{{form.field1.label}}
{% render form.field1 user action %}
{{form.field2.label}}
{% render form.field2 user action %}
Step three:
Something like:
def render(formfield, user, action, default_text="Private"):
if not user.is_authenticated():
action = "view"
if action == "view":
if user.is_authenticated():
fieldname = formfield.name
retval = str(getattr(formfield.form.model, fieldname))
else:
retval = default_text
else:
retval = formfield.as_widget()
return retval
Since you are saving the data, you must have a model attached to the form somehow, a modelform or not. So you can just use that model directly to get the values and render it in a template like you want.
The above suggestion would be possible, but since forms can be rather complex, it's probably not an easy task or worth the bother. Depends on how often you want to do this. But then it would probably be easier to create a filter for the model instead of the form.
Have I missed something
Forms not only display the field widgets but also handle the post data. A post sent would cause it to process the data cleanup, form and field error handling, etc.
It's kind of breaking the pattern - why create and render a form object only to tweak it not to look like a form?
If you are worried about too much work on templates, try to solve it with template inheritance in a best possible way. If you are very sure you want to change only the field tag, you can make sth like
{% if form %}
{% for error in form.field.errors %}
{{ error|escape }}
{% endfor %}
{{ form.field }}
{% else %}
{{ object.field }}
{% endif %}
for every field, but IMO that's not the point, YMMV.
Also what comes to mind (thinking of your solution) is dynamically attach widgets to form fields, but that'd be overengineering.
I have the same problem. Right now I have separate templates for display and editing; the former renders object fields, the latter form fields (but sometimes also object fields, for things which are not editable). The HTML structure can be quite complex: for example, on some pages I have large tables representing a multi-level hierarchy of objects. As a result, I end up with a large amount of duplicated code in the two templates, which is the opposite of DRY.
I have used template filters with form fields before, to save code when displaying errors together with the field. I think it would be a viable solution in this case. Another possibility may be to use a ModelForm subclass which can be told to render uneditable versions of the fields. This would help keep the templates simple. You could even render both the static and the editable version of a field, and use JavaScript to switch between them, activating and deactivating an editing mode.