Django template how to remove repeated values? - python

Is there a way to say to Django to hide/remove (show a blank space) for fields that got same values as previous row?
i.e.: if now is equal for differents Articles can it be show only for the first of the group?
from django.views.generic.list import ListView
from django.utils import timezone
from articles.models import Article
class ArticleListView(ListView):
model = Article
def get_context_data(self, **kwargs):
context = super(ArticleListView, self).get_context_data(**kwargs)
context['now'] = timezone.now()
return context
<h1>Articles</h1>
<ul>
{% for article in object_list %}
<li>{{ article.pub_date|date }} - {{ article.headline }}</li>
{% empty %}
<li>No articles yet.</li>
{% endfor %}
</ul>
Article - now
a - 2017-01-01
b -
c - 2017-01-02
d -
Is this possible from view or directly in template?

You can use ifchanged which:
Checks if a value has changed from the last iteration of a loop.
as follows:
<h1>Articles</h1>
<ul>
{% for article in object_list %}
<li>{{ article.headline }} - {% ifchanged article.pub_date|date %}
{{ article.pub_date|date }} {% endifchanged %}
</li>
{% empty %}
<li>No articles yet.</li>
{% endfor %}
</ul>
This will check in each iteration the value of article.pub_date and only when that value changes it will be displayed.
Good luck :)

Related

Django AdminInline on many-to-many relationship

I have two models like this:
class ArtCollection(models.Model):
# nothing important in this case
class Artwork(models.Model):
...
name = models.CharField(max_length=200, null=True, blank=True)
art_collections = models.ManyToManyField("ArtCollection", related_name="artworks")
image = models.ImageField(...)
Recently, I've change the relationship between them from FK for ArtCollection on Artwork model to m2m (as seen as above). What I would like to have now is something that I had before, particulary ArtworkInline in admin panel on ArtCollection change view (editable artwork fields like name, image change and so on). But it doesn't work. The only solution I've came across is this one (I know I should make an image preview rather than display its name - but its just an example):
from inline_actions.admin import InlineActionsMixin, InlineActionsModelAdminMixin
class ArtworkInline(admin.StackedInline):
model = ArtCollection.artworks.through
extra = 0
fields = ['artwork_image']
readonly_fields = ['artwork_image']
def artwork_image(self, instance):
return instance.artwork.image
artwork_image.short_description = 'artwork image'
class ArtCollectionAdmin(InlineActionsModelAdminMixin, admin.ModelAdmin):
...
inlines = [ArtworkInline]
Is it possible to have the editable fields in m2m relationship in inline django panel? I also use grappeli and custom template for inline (which are useless after changing the relationship - they have worked pretty well with FK, now I can have only readable_fields on default template).
{% extends 'admin/stacked_inline.html' %}
{% block fieldset %}
<fieldset class="module aligned {{ fieldset.classes }}">
{% for line in fieldset %}
{% with forloop.counter as counter %}
{% for field in line %}
{{ field.errors }}
{% if counter == 2 or counter == 6 %}
{% elif counter <= 7 %}
<p>{{ field.field }}</p>
{% endif %}
{% endfor %}
{% endwith %}
{% endfor %}
</fieldset>
{% if inline_admin_formset.formset.can_delete and inline_admin_formset.has_delete_permission and inline_admin_form.original %}
<span class="delete">{{ inline_admin_form.deletion_field.field }} {{ inline_admin_form.deletion_field.label_tag }}</span>
{% endif %}
{% endblock %}
Thanks for any advices.

How to get forloop.counter inside two forloops

I have a for loop inside another for loop and im trying to get the index (forloop.counter) from the inner loop. Django is for some reason giving me only the outer index.
{% for category in categories %}
{% for product in products %}
{% if product.category.name == category.name %}
<p>This is the amount of products inside this category: {{ forloop.counter }}<p>
{% endif %}
{% endfor %}
{% endfor %}
You can use forloop.parentloop to get to the outer forloop, so in this case {{forloop.parentloop.counter}}. {{forloop.counter}} gives me the inner loop already.
Return to the category view (e.g. in views.py) and add an annotation:
from django.db.models import Count
categories = Category.objects.annotate(num_products=Count('product'))
Remember to include the annotation in this view's context:
context.update({'categories': categories})
return render(request, 'myapp/categories.html', context)
Now, tweak your template to show the counts:
{% for category in categories %}
<p>This is the amount of products inside this category: {{ category.num_products }}<p>
{% endfor %}

How do I add pagination to my index.html ?

Here are my codes(it works fine):
#views.py
class IndexView(generic.ListView):
template_name = 'index.html'
context_object_name = 'home_list'
queryset = Song.objects.all()
paginate_by = 1
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context['all_artists']=Artist.objects.all()
context['all_songs']=Song.objects.all()
context['all_albums']=Album.objects.all()
return context
base.html(which is extended by index.html):
#base.html
{% block content %}{% endblock %}
{% block pagination %}
{% if is_paginated %}
<div class="pagination">
<span class="page-links">
{% if page_obj.has_previous %}
Previous
{% endif %}
<span class="page-current">
Page {{page_obj.number}} of {{page_obj.paginator.num_pages }}
</span>
{% if page_obj.has_next %}
Next
{% endif %}
</span>
</div>
{% endif %}
{% endblock %}
And my index.html:
{% extends 'base_generic.html' %}
{% block title %}<title>Listen to songs </title>{% endblock %}
{% block content %}
<h3>Best Songs</h3>
{% for song in all_songs %}
<ol>
<li>{{song.song_title}} <img src="{{song.song_logo}}" heigt=112, width=114/> <br></li>
</ol>
{% endfor %}
<h3>Best Albums</h3>
{% for album in all_albums %}
<ul>
<li title="{{album.album_title}}">
<img id="img_{{album.id}}" src="{{album.album_logo}}" heigt=112, width=114 />
<p>{{album.album_title}}</p>
</li>
</ul>
{% endfor %}
{% endblock %}
So when I compiled this, I got this window :
Image here
But in all pages, it stays the same.What I want is to display 1 song per page.Help guys !!!! :] :] :]
You never use your paginated objects, instead you've made a separate context variable called all_songs.
Simply just use the right context data
{% for song in all_songs %}
should be
{% for song in home_list %}
You may want to apply pagination for your other querysets too although it can get confusing paginating more than one list
Have a look here: https://www.youtube.com/watch?v=q-Pw7Le30qQ
The video explains pagination.
Alternative: https://docs.djangoproject.com/en/1.10/topics/pagination/
If you only want to display one song there is always the option to use a DetailView, which will only show one item.
Here is a stackoverflow question that describes the process for class based views: How do I use pagination with Django class based generic ListViews?
In your example: you don't have to set the queryset. Remove queryset = ### and add model = #YOURMODELNAME#.
If you want to overwrite the queryset you should do it in def get_queryset() which is a function of ListView. Like this:
class SongView(ListView):
model = Song
template_name = 'template_name'
def get_queryset():
queryset = super(SongView, self).get_queryset(**kwargs)
queryset = #aditional filters, ordering, whatever#
return queryset

Multiple Models in the single View (django, python)

.Hello everyone! I am a beginner in Django and I know that this question was asked hundrets of times on SO, but I still can't get it. I tried to use two models in the same IndexView, but it just repeats the elements which contains in the Petition model.
class IndexView(generic.ListView):
template_name = 'home.html'
context_object_name = 'home_list'
model = Petition
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context['petition'] = Petition.objects.all()
context['law'] = Law.objects.all()
return context
And here is a relevant part of the template:
{% if home_list %}
<ul>
{% for petition in home_list%}
<li>{{ petition.question }}</li>
<img src="{{ petition.image.url }}" height="200" width="300">
{% endfor %}
</ul>
{% else %}
<p>No petitions are available.</p>
{% endif %}
{% if home_list %}
<ul>
{% for law in home_list %}
<li>{{ law.question }}</li>
<img src="{{ law.image.url }}" height="200" width="300">
{% endfor %}
</ul>
{% else %}
<p>No laws are available.</p>
{% endif %}
You're defining your law list in the context as law but then you never reference it, you should be looping over these instead of home_list
{% if law %}
{% for l in law %} {# law is already defined so cant be used as scope var #}

Why doesn't Django recognize this in the template

I'd like to show my top level categories if the parent is equal to one. The topcats is a queryset that contains category items. However the code starred below is not working. It is not finding any cat items with parent = 1. Any idea why?
{% for cat in topcats %}
**{% if cat.parent == 1 %}**
<h3>{{ cat.category }}</h3>
{% for each in topcats %}
{% if each.parent == cat.id %}
<h5>{{ each }}</h5>
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
Note: parent is a TreeForeignKey in the database
I'd say cat.parent is a model object.
This should work for you:
{% if cat.parent.pk == 1 %}
However, this is quite hackish, as the parent node's id does not necessarily have a value of 1. The is_root_node() method is a better approach:
{% if cat.parent.is_root_node %}

Categories

Resources