Django related_name - python

I'm trying to do something like:
{% for property in current_listing %}
{% for property_image in property.property_images.all %}
{% endfor %}
{% endfor %}
But I would like something like:
{% for property in current_listing %}
{% for property_image in property.property_images.**ORDER_BY('-order')[0]** %}
{% endfor %}
{% endfor %}
How can I do this?

If I understand what you want, you can try custom template filter:
from django import template
register = template.Library()
#register.filter
def get_first_ordered_by(queryset, order):
return queryset.order_by(order)[0]
Then on a template:
{% load my_tags %}
{% with image=property.property_images.all|get_first_ordered_by:'-order' %}
{{ image }}
{% endwith %}
Note, that you can not use {% for %} since result of get_first_ordered_by is not iterable.

You can add a method to you Model's class definition that returns the query you want, then cann that method from you template.

Related

django regroup with duplicate nametuple

I have code for regroup in django template, like below:
{% regroup clients by title.0 as clients_list %}
{% for client in clients_list %}
{{ client.grouper }}
{% for item in client.list %}
{% if item.client_link %}
{{ item.title }}
{% else %}
{{ item.title }}
{% endif %}
{% endfor %}
{% endfor %}
Sometime I have duplicate nametuple in my results for the same letter, for example - 'd':
GroupedResult(grouper='d', list=[<Client: decompany_1>]) GroupedResult(grouper='d', list=[<Client: decompany_2>])
so in result I have two headers with letter 'd'
Someone know, how to avoid this?
edit
views.py
class ClientsListView(ListView):
model = Client
template_name = 'clients/clients_list.html'
context_object_name = 'clients'

Django Nested Template Tags

I have a custom template tag that accesses a models function. However, I also need the custom template tag to be in a for loop, which requires nested template tags:
{% load custom_tags %}
{% for list in remind_lists %}
<h3>{{ list.title }}</h3>
{% for item in {% get_list_items user.username %} %}
<p>{{ item.title }}</p>
{% endfor %}
{% endfor %}
It gives me a TemplateSyntaxError- 'for' statements should use the format 'for x in y': for item in {% get_list_items user.username. Is there anyway I can do this?
custom tag:
register = template.Library()
#register.simple_tag
def get_list_items(event_ins, authenticated_user):
return event_ins.get_list_items(authenticated_user)
You can't nest tags in this way - but you can assign the output of the tag to a variable that you can then loop over:
{% load custom_tags %}
{% for list in remind_lists %}
<h3>{{ list.title }}</h3>
{% get_list_items list user.username as list_items %}
{% for item in list_items %}
<p>{{ item.title }}</p>
{% endfor %}
{% endfor %}
# you can format the text or data in the function itself and return the same to the template
{% for list in remind_lists %}
<h3>{{ list.title }}</h3>
{{ list.id|get_list_items:authenticated_user }}
{% endfor %}
register = template.Library()
#register.simple_tag
def get_list_items(event_ins, authenticated_user):
# you can format the text or data here
return ...

adding form styling to django forms

I am currently in the process of adding a theme to the admin of django one issue I have found it adding styling to the forms is that it is very difficult and I can't find much useful documentation on it. The only real thing I need to do is add classes to the form elements so that they match the theme I am using is this possible and if so how would you go about doing it the code I am currently using is very basic and the basic code included in the standard theme does anybody know how to add classes to these standard bits of code bellow is what I have.
{% if is_popup %}
<input type="hidden" name="_popup" value="1" />
{% endif %}
{% if save_on_top %}
{% block submit_buttons_top %}
{% submit_row %}
{% endblock %}
{% endif %}
{% if errors %}
<p class="errornote">
{% blocktrans count counter=errors|length %}
Please correct the error below.
{% plural %}
Please correct the errors below.
{% endblocktrans %}
</p>
{{ adminform.form.non_field_errors }}
{% endif %}
{% block field_sets %}
{% for fieldset in adminform %}
{% include "admin/includes/fieldset.html" %}
{% endfor %}
{% endblock %}
{% block after_field_sets %}{% endblock %}
{% block inline_field_sets %}
{% for inline_admin_formset in inline_admin_formsets %}
{% include inline_admin_formset.opts.template %}
{% endfor %}
{% endblock %}
{% block after_related_objects %}{% endblock %}
{% block submit_buttons_bottom %}
{% submit_row %}
{% endblock %}
There are a lot of ways to do this, but certainly one way would be to overwrite all the widgets in your ModelAdmin rather than in the template. That could look something like this:
from django.db import models
from django.contrib import admin
from django.forms.extras.widgets import TextInput
class MyModelAdmin(admin.ModelAdmin):
formfield_overrides = {
models.TextField: {'widget': TextInput(attrs={'class':'my-widget-class'},)},
}
You'd have to go through and do that for each widget, but then they'd have the appropriate classes -- at least for that modelAdmin.

How to use a for loop inside a Django conditional?

Basically if there is a certain GET parameter in the url (in this case "latest") I want to slice the object list by a different number than the usual. But doing this:
{% if 'latest' in request.GET %}
{% for object in object_list|slice:"22" %}
{% else %}
{% for object in object_list|slice:"10" %}
{% endif %}
// blah blah
{% endfor %}
causes a syntax error since Django expects a closing endfor instead of the else. Is there any way to use for loops inside conditionals?
You need to have a body in your for loop.
{% if 'latest' in request.GET %}
{% for object in object_list|slice:"22" %} {{ object }} {% endfor %}
{% else %}
{% for object in object_list|slice:"10" %} {{ object }} {% endfor %}
{% endif %}
Without it, you're saying the equivalent of the following Python code:
if 'latest' in request.GET:
for object in slice(object_list, 22):
#No code here
else:
for object in slice(object_list, 10):
#No code here
which obviously is an error.
Just close the for loop inside each conditional:
{% if 'latest' in request.GET %}
{% for object in object_list|slice:"22" %}
{{ object.name }}
{% endfor %}
{% else %}
{% for object in object_list|slice:"10" %}
{{ object.name }}
{% endfor %}
{% endif %}

How can I concatenate forloop.counter to a string in my django template

I am already trying to concatenate like this:
{% for choice in choice_dict %}
{% if choice =='2' %}
{% with "mod"|add:forloop.counter|add:".html" as template %}
{% include template %}
{% endwith %}
{% endif %}
{% endfor %}
but for some reason I am only getting "mod.html" and not the forloop.counter number. Does anyone have any idea what is going on and what I can do to fix this issue? Thanks alot!
Your problem is that the forloop.counter is an integer and you are using the add template filter which will behave properly if you pass it all strings or all integers, but not a mix.
One way to work around this is:
{% for x in some_list %}
{% with y=forloop.counter|stringformat:"s" %}
{% with template="mod"|add:y|add:".html" %}
<p>{{ template }}</p>
{% endwith %}
{% endwith %}
{% endfor %}
which results in:
<p>mod1.html</p>
<p>mod2.html</p>
<p>mod3.html</p>
<p>mod4.html</p>
<p>mod5.html</p>
<p>mod6.html</p>
...
The second with tag is required because stringformat tag is implemented with an automatically prepended %. To get around this you can create a custom filter. I use something similar to this:
http://djangosnippets.org/snippets/393/
save the snipped as some_app/templatetags/some_name.py
from django import template
register = template.Library()
def format(value, arg):
"""
Alters default filter "stringformat" to not add the % at the front,
so the variable can be placed anywhere in the string.
"""
try:
if value:
return (unicode(arg)) % value
else:
return u''
except (ValueError, TypeError):
return u''
register.filter('format', format)
in template:
{% load some_name.py %}
{% for x in some_list %}
{% with template=forloop.counter|format:"mod%s.html" %}
<p>{{ template }}</p>
{% endwith %}
{% endfor %}
You probably don't want to do this in your templates, this seems more like a views job: (use of if within a for loop).
chosen_templates=[]
for choice in choice_dict:
if choice =='2':
{% with "mod"|add:forloop.counter|add:".html" as template %}
template_name = "mod%i.html" %index
chosen_templates.append(template_name)
Then pass chosen_templates to your template where you will have only
{% for template in chosen_templates %}
{% load template %}
{% endfor %}
Also, I don't quite understand why you are using a dict to select the template with a number that is not in the dictionnary. for key,value in dict.items() may be what you are looking for.
Try without using the block "with"
{% for choice in choice_dict %}
{% if choice =='2' %}
{% include "mod"|add:forloop.counter|add:".html" %}
{% endif %}
{% endfor %}

Categories

Resources