in my templates/videos.html,
<div class="grid grid-cols-3 gap-2">
{% for vid in videos.streams.filter(audio_only=True) %}
{{vid.resolution}}
{% endfor %}
</div>
Error is,
Could not parse the remainder: '(audio_only=True)' from 'videos.streams.filter(audio_only=True)'
I can solve this when i pass all_videos = videos.streams.filter(audio_only=True) from my views.py as context, and in templates/videos.html i replace videos.streams.filter(audio_only=True) with all_videos,
but I want to know that is there any other method to solve this
but I want to know that is there any other method to solve this.
You could add an extra property/method with no parameters to the Video model and call that property to obtain the filtered queryset.
For example:
class Video(models.Model):
# …
#property
def audio_streams(self):
return self.streams.filter(audio_only=True)
and then thus use {% for video in videos.audio_streams %}. But regardless, the Django template language has been deliberately restricted to prevent people from writing this: a template should implement rendering logic, not business logic: business logic belongs in the models and the views. So the only clean solution is to filter in the view, not the template.
Related
I would like to know if anyone has any best practice recommendations for rendering a view within a view in Django, or something with a similar effect where both views can have their own context and methods.
I am currently rendering the dropdown using the built-in include tag. So the nested .html is using the same Django view as the rest of the page. And all the context is coming from the main view as shown below. I would like to give this dropdown its own Django view so that I only perform certain database queries and other calculations if the dropdown is opened.
<div class="container-fluid">
<div class="row">
<div class="col-6">
</div>
<div class="col-2 d-flex justify-content-center">
{% include nested.html %}
</div> ...
It would be nice if someone with experience in this could let me know what they think, and if it even makes sense to try and split this into 2 views.
In summary. I would like to know if I can somehow render a separate view using something similar to the include Django tag. So that I have control over where the view gets rendered.
Below I have outlined my implementation of the solution below, using custom inclusion tags as suggested in the comments to my question.
You can make a custom template tag file in project directory and then register these in the template library. e.g:
template_tags.py
from django import template
from users.models import Organisation
register = template.Library()
#register.inclusion_tag('nested.html', takes_context=True)
def nested_template(context, param=None): #param to pass variables from main view
context.update({
'data_list': get_data_list(param)
'organisation_id': param,
})
return context
def get_data_list(self,param):
data_list = ... #do all queries needed.
return data_list
In the template tag you point to your nested.html which does whatever you need it to do. For example:
nested.html
{% for data in data_list %}
<h4> {{data}} </h4>
{% endfor %}
Then to include the template, in your main view template:
{% load nested_template %} #at the top or anywhere before using it
{% nested_template param %} #where you want the template included
Hopefully clear enough and may assist someone
I'm new to Django. The question is rather basic and I read some google links and documents, apparently I can't resolve it.
Basically:
I need to access the blog entries of a particular blog inside html file, but apparently blog.blogentry_set() is not working as expected. Could someone help please. Here is the code I tried:
models.py file:
class Blog(models.Model):
subject = models.CharField(max_length = 20)
...
class BlogEntry(models.Model):
ref = models.ForeignKey(Blog)
...
index.html file:
{% for blog in blogs %}
<p>{{ blog.subject}}</p>
<div>
<p>{{blog.date}}</p>
{% for entry in blog.blogentry_set.all() %}
{{entry.text}}
{% endfor %}
</div>
{% endfor %}
I tried to delete (), and this helps to take off the error message, but the entry text is not printed as expected, so something is again not working.
I heard in template language, to call function we do not need (), but then how do we pass arguments?
also, I am asking to myself: do I need to 'load' some file here? Please help :D
You can't pass an argument to a callable attribute like this. Either pull the value in the view, or write a custom template tag to do it.
To address the first problem ("blog.blogentry_set() is not working as expected"), remove the parenthesis after the .all like:
{% for entry in blog.blogentry_set.all %}
{{entry.text}}
{% endfor %}
The second issue ("to call function we do not need (), but then how do we pass arguments?"), is amply addressed by #Varnan K's answer. You will likely have to create a custom template tag.
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.
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 %}
I need to perform a filtered query from within a django template, to get a set of objects equivalent to python code within a view:
queryset = Modelclass.objects.filter(somekey=foo)
In my template I would like to do
{% for object in data.somekey_set.FILTER %}
but I just can't seem to find out how to write FILTER.
You can't do this, which is by design. The Django framework authors intended a strict separation of presentation code from data logic. Filtering models is data logic, and outputting HTML is presentation logic.
So you have several options. The easiest is to do the filtering, then pass the result to render_to_response. Or you could write a method in your model so that you can say {% for object in data.filtered_set %}. Finally, you could write your own template tag, although in this specific case I would advise against that.
I just add an extra template tag like this:
#register.filter
def in_category(things, category):
return things.filter(category=category)
Then I can do:
{% for category in categories %}
{% for thing in things|in_category:category %}
{{ thing }}
{% endfor %}
{% endfor %}
I run into this problem on a regular basis and often use the "add a method" solution. However, there are definitely cases where "add a method" or "compute it in the view" don't work (or don't work well). E.g. when you are caching template fragments and need some non-trivial DB computation to produce it. You don't want to do the DB work unless you need to, but you won't know if you need to until you are deep in the template logic.
Some other possible solutions:
Use the {% expr <expression> as <var_name> %} template tag found at http://www.djangosnippets.org/snippets/9/ The expression is any legal Python expression with your template's Context as your local scope.
Change your template processor. Jinja2 (http://jinja.pocoo.org/2/) has syntax that is almost identical to the Django template language, but with full Python power available. It's also faster. You can do this wholesale, or you might limit its use to templates that you are working on, but use Django's "safer" templates for designer-maintained pages.
The other option is that if you have a filter that you always want applied, to add a custom manager on the model in question which always applies the filter to the results returned.
A good example of this is a Event model, where for 90% of the queries you do on the model you are going to want something like Event.objects.filter(date__gte=now), i.e. you're normally interested in Events that are upcoming. This would look like:
class EventManager(models.Manager):
def get_query_set(self):
now = datetime.now()
return super(EventManager,self).get_query_set().filter(date__gte=now)
And in the model:
class Event(models.Model):
...
objects = EventManager()
But again, this applies the same filter against all default queries done on the Event model and so isn't as flexible some of the techniques described above.
This can be solved with an assignment tag:
from django import template
register = template.Library()
#register.assignment_tag
def query(qs, **kwargs):
""" template tag which allows queryset filtering. Usage:
{% query books author=author as mybooks %}
{% for book in mybooks %}
...
{% endfor %}
"""
return qs.filter(**kwargs)
EDIT: assignment_tag was removed in Django 2.0, this will no longer work.
For anyone looking for an answer in 2020.
This worked for me.
In Views:
class InstancesView(generic.ListView):
model = AlarmInstance
context_object_name = 'settings_context'
queryset = Group.objects.all()
template_name = 'insta_list.html'
#register.filter
def filter_unknown(self, aVal):
result = aVal.filter(is_known=False)
return result
#register.filter
def filter_known(self, aVal):
result = aVal.filter(is_known=True)
return result
In template:
{% for instance in alarm.qar_alarm_instances|filter_unknown:alarm.qar_alarm_instances %}
In pseudocode:
For each in model.child_object|view_filter:filter_arg
Hope that helps.
This is my approach:
#register.filter()
def query_filter(value, attr):
return value.filter(**eval(attr))
In the template:
{{ queryset|query_filter:'{"cod_tipoinmueble":1,"des_operacion": "alquiler"}'|length }}