django templates accessing a dict value based on key - django

in my views.py i obtain 5 dicts, which all are something like {date:value}
all 5 dicts have the same length and in my template i want to obtain some urls based on these dicts, with the common field being the date - as you would do in an sql query when joining 5 tables based on a common column
in python you would do something like:
for key, value in loc.items():
print key, loc[key], ctg[key], sctg[key], title[key], id[key]
but in django templates all i could come up with is this:
{% for lock, locv in loc.items %}
{% for ctgk, ctgv in ctg.items %}
{% for subctgk, subctgv in subctg.items %}
{% for titlek, titlev in titlu.items %}
{% for idk, idv in id.items %}
{% ifequal lock ctgk %}
{% ifequal ctgk subctgk %}
{% ifequal subctgk titlek %}
{% ifequal titlek idk %}
<br />{{ lock|date:"d b H:i" }} - {{ locv }} - {{ ctgv }} - {{ subctgv }} - {{ titlev }} - {{idv }}
.... {% endifequals & endfors %}
which of course is ugly and takes a lot of time to be rendered
right now i am looking into building a custom tag, but i was wondering if you guys have any feedback on this topic?

Sounds to me like you need to use something other than aligned dicts. How about a dict of a small class, which contains the things you want:
class MyThing:
def __init__(self, loc, ctg, sctg, title, id):
self.loc = loc
self.ctg = ctg
self.sctg = sctg
self.title = title
self.id = id
Would that make your template code a bit less painful? (Apologies if I've misunderstood the problem - I'm having a hard time following your nested ifs!).

Django templates should try to resolve variables with dot as a dictionary lookup (if varaible is an dictionary). So ctg.key equals to ctg[key]. Did you try this:
{% for key, value in loc.items %}
{{ key|date:"d b H:i" }} - {{ value }} - {{ ctg.key }} - {{ subctg.key }} - {{ title.key }} - {{ id.key }}

Related

Checking for widget attribute in Django templates

I'd need to pass some data from my manually generated form to the template, and would need to check the presence of that information there.
I'm generating my form as such (in the __init__ part):
for i in days_in_month:
self.fields["info_%s" % i] = forms.ChoiceField(label="%s" % i.strftime("%a %d-%m-%Y"),
required=False,
choices=Information._meta.get_field('info').choices,
widget=forms.Select(attrs={'something': 'test'}))
What I would like to do, is to check in the template whether the attribute something is set, and if so, display its value (in the example above: test).
Any idea?
I tried with {{ field.attribute }} as per Access form field attributes in templated Django and the below:
{% for field in form %}
{{ field.label_tag }} {{ field }}
{{ field.widget.attrs.something }}
{% endfor %}
... but that doesn't work (invalid).
Ultimately I want to do something similar to:
{% if field.widget.attrs.something %}{{ field.widget.attrs.something }}{% endif %}
That would be
{{ field.field.widget.attrs.something }}

Annotate results with foreignkey

I'd like to filter an object in Django, and return it along with any objects for which the results are a ForeignKey. I'm not sure if annotation is what I need here, or something else.
This is my model:
class Dress(models.Model):
name = models.CharField(...)
price = models.FloatField(...)
class ClothingSize(models.Model):
code = models.CharField(...)
class DressSizeAvailable(models.Model):
dress = models.ForeignKey(Dress)
size = models.ForeignKey(ClothingSize)
Say I want to filter all dresses under $50, and then display them with the available sizes. What is the best way to do this?
I've got as far as this:
# In view
results = Dress.objects.filter(price__lt=50)
# How to annotate with available sizes?
# In template
{% for result in results %}
{{ result.name }}, ${{ result.price }}
Sizes: {{ ??? }}
{% endfor %}
### 1st solution (similar to Daniel Rosenthal's answer but with performances concern)
results = DressSizeAvailable.objects.filter(dress__price__lt=50).select_related('dress', 'size')
# then you can browse your DressSizeAvailables as you wish in your template. The select related allows you NOT TO query the database again when you generate your template
### 2nd solution
results = Dress.objects.filter(price__lt=50).prefetch_related('dresssizeavailable_set__dress')
{% for dress in results %}
{{ dress.name }}, ${{ dress }}
Sizes: <ul>
{% for dsa in dress.dresssizeavailable_set %}
<!-- Thanks to the prefetch_related, we do not query the base again here -->
<li>{{ dsa.size.code }}</li>
{% endfor %}
</ul>
{% endfor %}
You'll need to give your template a queryset (or something similar) of DressSizeAvailable objects. So first you'll need to get all the Dress objects you're interested, and then filter DressSizeAvailable based on those Dresses
so in your view:
dresses = Dress.objects.filter(price__lt=50)
dress_size_available = []
for dress in dresses:
available = DressSizeAvailable.objects.filter(dress=dress)
dress_size_available.append(available)
Then render your template, passing it the variable dress_size_available
Your template can then be rather simple.
{% for dsa in dress_size_available %}
{{ dsa.dress.name }}, ${{ dsa.dress.price }}
Size: {{ dsa.size }}
{% endfor %}

Django DRY List iteration

As someone who is just starting to use Django in my scarce time, I appreciate in advance your time in helping me learn how to make my code cleaner and correct.
I have two lists comprised of two querysets as follows:
company_list = [Company_stats.objects.filter(period__exact=P, company_name__in=master_names)]
industry_list = [Industry_stats.objects.filter(period__exact=P, industry_name__in=master_names)]
I iterate through both lists in my template to create a small table.
{%for c in company_list%}
{%for z in c %}
{{ z.company_name }}
{{ z.nxt_m_ret_est }}
{{ z.nxt_m_ret_rat }}
{% endfor %}
{% endfor %}
{%for c in industry_list%}
{%for z in c %}
{{ z.industry_name }}
{{ z.nxt_m_ret_est }}
{{ z.nxt_m_ret_rat }}
{% endfor %}
{% endfor %}
This works fine, however, since I am using the same code except for z.industry_name vs. z.company_name I was wondering whether you could help me figure out a better way to do this.
I have tried combining the lists into one list with both querysets in it and that works except for the obvious issue that I don't know how to tell it to retrieve z.company_name or z.industry_name depending on the queryset where the data is coming from, because everything became part of the same list.
Once you've changed the field to name on both models you can put both querysets into the same list and then iterate over that.
master_list = [model.objects.filter(period__exact=P, name__in=master_names) for model in (Company_stats, Industry_stats)]
...
{% for l in master_list %}
{% for i in l %}
{{ i.name }}
{{ i.nxt_m_ret_est }}
{{ i.nxt_m_ret_rat }}
{% endfor %}
{% endfor %}
If you want to have the code be more generic, it would help to make your names more generic. Would it be possible for you to change industry_name and company_name to just name throughout your system?

Django template vars and list indices

I have a strange problem.
I use paginator to display some data in each page, however, I do not see any possibility to add other attributes I need to the model, so I have created another list of dicts with additional data.
In template:
{% for x in p.object_list %}
{% with c=forloop.counter0 %}
{{ info.c }} <!-- prints nothing, while {{ info }} prints all the list of dicts and {{ c }} prints 0, for example. {{ info.0 }} prints everything as intended too. -->
{% endwith %}
{% endfor %}
{{ info.c }} accesses info['c'], info.c, etc. You want the slice filter instead.

django templates question

How can I get the value of form.field in template. I mean not the html input element of the field but the value inside the input?
To get the bound data (in 1.2.3)
{{ form.field.data }}
In the development version, it's {{ form.field.value }} which automatically pulls initial data OR bound data whereas it's an explicit call in the current release:
form.field.field.initial or form.field.data
Update: the admin forms work differently. First of all, the BoundField is {{ adminfield.field }} and not {{ adminfield }} in your comment, but we have bigger problems.
On the change form, the form is not bound so data can only be pulled from the initial dictionary passed into the form constructor. It's not accessible via the django template syntax.
Here's the relevant lines in BoundField:
if not self.form.is_bound:
data = self.form.initial.get(self.name, self.field.initial)
# you can't do this kind of lookup from the template.
The only way to access this type of info from the template without making a template tag (which you should!) is to loop through each key/value in the initial dictionary and comparing to the current fields name.
{% for line in fieldset %}
{% for adminfield in line %}
{% for k, v in adminfield.field.form.initial.items %}
{% if k == adminfield.field.name %}
{{ k }}:{{ v }}
{% endif %}
{% endfor %}
{% endfor %}
{% endfor %}