How to avoid repetition on templates in Django? [duplicate] - python

This question already has answers here:
How to make a reusable template in Django?
(8 answers)
Closed 5 years ago.
I have the following code that is repeated on several templates:
{% for element in elements %}
<div class="some-class">
<div class="another-class">
<div class="row">
<div class="col-xs-3">
<img class="img-responsive" alt="{{ entry.user }} avatar" style="border-radius: 50%; width: 100%;" src="{{ entry.avatar_url}}">
</div>
<div class="col-xs-9" style="some-style">
{% if entry.data1 %}<small>{% trans entry.data1 %}</small><br>{% endif %}
{% trans entry.data2 %} {% trans entry.data2 %}
<br>
<small style="some-style">
{% blocktrans with timestamp=entry.timestamp|naturaltime %}
{{ timestamp }}
{% endblocktrans %}
</small>
</div>
</div>
</div>
</div>
{% endfor %}
I was wondering what is the best way to avoid repeating this piece of code, I am kind of newbie to Django, and I would really appreciate your help.
Edit:
What if I need to pass a content to that template. Is it going to use the same context than the one in the containing file or should I indicate the context in some way?

That is easy:
Put this piece of HTML in a file called, say reusable.html and then include it in other templates.
Like this:
<!-- Other HTML -->
... html stuff here
{% include 'reusable.html' %}
Now, if you want to pass a parameter to reusable.html, you do it like this:
`{% include 'reusable.hmtl' with var_a='abc' var_b=123 %}`

Set it up in it's own template, for example new_template.html and use {% include 'new_template.html' %} wherever you want it

Related

Select first image of image foreign key in django template

I want to select first image of an object property set. I created a Property Model with a Foreign Key to an PropertyImages model. How do I access the first image of the property object_set.all in the template. I don;t want to do it in the view function since this should be in the base.html file.
the code:
{% for property in properties %}
<div
style="background-image: url('{{property.propertyimages_set.all|first.url}}'); background-size: 100% 100%; "
;
class="tm-row-featured"
>
<div class="featured-content">
<p><span>Name: </span>{{property.property_name}}</p>
<hr>
<p><span>Type: </span>{{property.property_type}}</p>
<p><span>Price: </span>₦{{property.price}}</p>
<p><span>Location: </span>{{property.property_state}}</p>
<p><a href="{% url 'property_details' property.property_slug %}">More info
>>></a></p>
</div>
</div>
{% endfor %}
You can use forloop.first to check if the loop is executed first and then use an appropriate if tag to display the image. Please see the for loop related variables from the link below:
Ref: https://docs.djangoproject.com/en/4.0/ref/templates/builtins/#for
{% if forloop.first %}
# Show first image here
{% endif %}
Try this:
Ref
<div style="background-image: url('{{properties.0.propertyimages_set.url}}'); background-size: 100% 100%;"; class="tm-row-featured">
<div class="featured-content">
<p><span>Name: </span>{{properties.0.property_name}}</p>
<hr>
<p><span>Type: </span>{{properties.0.property_type}}</p>
<p><span>Price: </span>₦{{properties.0.price}}</p>
<p><span>Location: </span>{{properties.0.property_state}}</p>
<p>More info >>></p>
</div>
</div>
The solutions above didnt work for me. I finally found a way around the solution thus:
{% for property in properties %}
<div
{% with property.propertyimages_set.all|first as photo %} style="background-image: url('{{photo.image.url}}'); background-size: 100% 100%; "
; {% endwith %}
class="tm-row-featured"
>
<div class="featured-content">
<p><span>Name: </span>{{property.property_name}}</p>
<hr>
<p><span>Type: </span>{{property.property_type}}</p>
<p><span>Price: </span>₦{{property.price}}</p>
<p><span>Location: </span>{{property.property_state}}</p>
<p>More info >>></p>
</div>
</div>
{% endfor %}
</div>

Can I use a for loop counter where there is a number in the property names in Django?

I have this html code but I have 20 products and the only code that changes in them are the image1 caption1 product1 etc.
I'm new to Django and not sure if this can be done with a for loop using a counter or if it can be done with an {% include ___ with ____ %}? Or can it be done with Python code? I'm even newer to Python and wouldn't be sure how to do that.
I tried a for loop counter but it said i couldnt do {% image page.image{{ forloop.counter }} fill... %} as it expects the %} before the {{ }}
{# Product1 #}
<div class="document product-card">
<div class="w3-card-4 w3-margin w3-white" data-aos="fade-down">
{% image page.image1 fill-150x150-c100 %}
<div class="w3-container">
</div>
<hr>
<p id="caption">{{ page.caption1 }}</p>
{% for download in page.product1.all %}
{% with doc=download.product1 %}
<div class="download product-info">
<a href="{{ doc.url }}" class="smooth-over-button noDecoration">
<i class="fa fa-download"></i>
<p class="btn-txt">{{ doc.title }}</p>
</a>
</div>
{% endwith %}
{% endfor %}
</div>
</div>
The with statement inside your loop is doing a cache, so the doc variable that you are creating will always point to your first product.
I suggest that you drop the with completely and instead reference the document with the full name.
Also, it feels like there could be a logic error somewhere else, or at least some poorly named variables, since you are referencing a product1 in page and then a product1 in download.
If you are new to python but have experience with another languages, is better if you treat the for statement as a foreach, as python doesn’t have the traditional for logic.
try this:
page.image|add:forloop.counter
page.caption|add:forloop.counter
page.product|add:forloop.counter

Django: Extent with snippets or better solution

I have the following template:
{% extends "account/base.html" %}
{% load i18n %}
{% load account %}
{% load crispy_forms_tags %}
{% block head_title %}{% trans "Password Reset" %}{% endblock %}
{% block content %}
<div class="container">
<div class="row justify-content-center">
<div class="col-8">
<h1>Reset your password</h1>
{% if user.is_authenticated %}
{% include "account/snippets/already_logged_in.html" %}
{% endif %}
<p>{% trans "Forgotten your password? Enter your e-mail address below, and we'll send you an e-mail allowing you to reset it." %}</p>
<form method="POST" action="{% url 'account_reset_password' %}" class="password_reset">
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="btn btn-primary">Reset My Password</button>
</form>
<p><em>{% blocktrans %}Please contact us if you have any trouble resetting your password.{% endblocktrans %}</em></p>
</div>
</div>
</div>
{% endblock %}
account/base.html contains this here:
{% extends "base.html" %}
base.html then contains tags etc. I am currently struggling with finding the best solution while considering DRY. In my template I have written:
<div class="container">
<div class="row justify-content-center">
<div class="col-8">
[more text]
</div>
</div>
</div>
I have several of these templates and in each of them I am currently writing the same ... I am now wondering is the right solution to include these opening / closing div-tags in two files and then add
{% include "div-open.html" %}
[more text]
{% include "div-closing.html" %}
Or is there any better solution to this? It doesn't feel right, that's why I am asking you now how you would solve this.
I depends if HTML repetition should be considered as DRY violation. I you have custom form fields which you want to include, than having {% include 'simple_custom_field.html' with field=form.some_fied %} where
simple_custom_field.html
<input
type="{{ field.field.widget.input_type }}"
class="form-control {{ field.field.widget.attrs.class }} {{ class }}"
id="{{ field.id_for_label }}"
name="{{ field.html_name }}"
placeholder="{{ field.label }}"
{% if field.value is not None %} value="{{ field.value }}"{% endif %}>
or like that...
is good idea, or you can render whole form like that also if you have long blocks or separate blocks of HTML in multiple files, then go for it. But its bad idea for including simple and fundamental parts of HTML. It should be transparent for the programmer.
If you want to do it another way, there are ways how to add custom template tags and "modify" the language you write templates in.
Here is docs how to do it: Writing custom template tags | Django docs

Getting a total number of objects inside each object using django markup

Using Django, I am trying to output the total number of lots in each community.
A community has several lots, and there are several communities. Here is an example of what I am getting:
Total lots: 99.
This community only has 2 lots. There are 4 communities with a total of 9 lots between them.
The models and views seem correct. Is there a filter I am missing or a different way of writing this to get the correct result?
{% if community.is_active %}
<a class="panel-link" href="{% url 'community-detail' pk=community.id %}" %}>
<div class="col-md-6 community_col">
<div class="community_box">
<div class="row">
<br>
<div class="col-md-4 community_img">
<img src="/media/{{ community.logo }}" alt="">
</div>
<div class="col-md-7 col-md-offset-1">
<h1 style="margin-bottom: -10px; margin-top: -15px;"><small>{{ community.name }}</small></h1>
<h4>{{ community.city }}, {{ community.state }}</h4>
<h6>Total lots: {% for lot in community.lot_set.all %}{{ lots|length }}{% endfor %}</h6>
<h6>Total Active lots: </h6>
<h6>Total Sold lots: </h6>
<h6>Total Inactive lots: </h6>
</div>
</div>
</div>
</div>
</a>
{% endif %}
{% endfor %}
This logic:
{% for lot in community.lot_set.all %}{{ lots|length }}{% endfor %}
Iterates through each lot object. You then take the length of lots which as far as I can tell is not a variable in context. If you wanted to just count the objects:
{{ community.lot_set.count }}
would do.
Looking ahead though, you're going to want to get counts of Active, Sold, Inactive, etc, and to do this efficiently you should look into annotating the queryset and doing this counting in the database:
https://docs.djangoproject.com/en/1.11/topics/db/aggregation/#generating-aggregates-for-each-item-in-a-queryset

Django 1.8 calls to database in html code

long-time lurker for this website, but I finally decided to join the community.
I have a quick question on some of my code. I took a job this year for my university developing a website for the journalist department. The website was being built the previous year by another student using Django 1.8, python 2, and everything else that comes with that. I knew a decent amount about these languages, and I have learned a lot testing out different methods for hours on end. However, there is one thing I am having trouble with that I have researched for forever.
Basically, for my website, I have different "sections" for different pages of articles. These articles have many traits. One trait is called "section" and this section has the names of the pages. So for example:
One page is named "look". I can call my code and display all of my featured_articles. HOWEVER, I am trying to only display the articles where the name of the section equals "look".
Here is my current code. Any ideas? I have tried many things but I can't get it to work properly. For loops, if statements, different HTML processes, different pages in django, etc...
{% for article, section in featured_articles %}
<div class="media panel panel-default">
<div class="panel-body">
<div class="media-left">
<a href="articles/{{ article.url }}">
<img class="media-object thumbnail-featured"
src="{{ article.image }}">
</a>
</div>
<div class="media-body">
<a href="articles/{{ article.url }}">
<h3 class="media-heading">{{ article.title }}</h3>
</a>
<!-- TODO figure out how to iterate through the authors field, manytomany -->
{% for contributor in article.authors.all %}
<p>{{ section.name }} |
{{contributor}}</p>
{% endfor %}
<p>{{article.preview}}</p>
</div>
</div>
</div>
{% endfor %}
Thank you for any help!!
Overall, it is a not such a good idea. You are sending all data to the template engine and doing the filtering there?
Why not filter it in the view function / view class and then return that data inside a template variable and then render in the front end?
def detail(request, poll_id):
filtered_data = .......objects.get(name='look')
return render(request, 'polls/detail.html', {'look_data': filtered_data})
{% for article, section in look_data %}
<div class="media panel panel-default">
.... blah blah blah
</div>
{% endfor %}
As I understand, you just need to add if statement:
{% for article, section in featured_articles %}
{% if section.name == 'look' %}
<div class="media panel panel-default">
<div class="panel-body">
<div class="media-left">
<a href="articles/{{ article.url }}">
<img class="media-object thumbnail-featured"
src="{{ article.image }}">
</a>
</div>
<div class="media-body">
<a href="articles/{{ article.url }}">
<h3 class="media-heading">{{ article.title }}</h3>
</a>
<!-- TODO figure out how to iterate through the authors field, manytomany -->
{% for contributor in article.authors.all %}
<p>{{ section.name }} |
{{ contributor }} </p>
{% endfor %}
<p>{{article.preview}}</p>
</div>
</div>
</div>
{% endif %}
{% endfor %}

Categories