Django and HTML template : Group by panels with common object attributes - django

One more time, I come back to you in order to get advices or your help.
I'm displaying in my django template a list of objects and I would like to sort them through a common attributes : category.
Each object displayed (a publication) gets some attributes : category, format, language ...
For example :
The white text with blue background indicates the category. I have 2 publications with category = BIOLOGICAL STANDARDISATION PROGRAMME and 1 publication with category = TEST
I would like to group both BIOLOGICAL STANDARDISATION PROGRAMME in one panel but I don't find a way to do that.
This is my HTML template file :
{% for element in test_research|dictsort:"publication.category.name" %}
<div class="col-sm-12">
<div class="panel panel-default request-panel">
<div class="panel-heading" role="tab">
<h4 class="panel-title">
{{ element.publication.category }}
</h4>
</div>
<div class="panel-body">
<div class="row">
<div class="col-sm-9">
<p class="request-publication">{{ element.publication }} </p>
</div>
<div class="col-sm-3 request-cover">
{% if element.publication.cover %}
<a href="{{ element.publication.cover.url }}" target="_blank">
{% thumbnail element.publication.cover "40x40" crop="center" as im %}
<img src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}">
{% endthumbnail %}</a>
{% endif %}
</div>
</div>
</div>
<div class="panel-footer">
<div class="row">
<table>
<tbody>
<tr>
<td class="col-md-1">
<div class="material-switch pull-right">
<input id="someSwitchOptionSuccess_{{ element.id }}" name="DocumentChoice" type="checkbox"
value="{{ element.id }}"/>
<label for="someSwitchOptionSuccess_{{ element.id }}" class="label-success"></label>
</div>
</td>
<td class="col-md-1 request-language"> {{ element.language }}</td>
<td class="col-md-1 request-format">
{% if element.format == 'pdf' %}
<span class="badge alert-danger">{{ element.format }}</span>
{% endif %}
{% if element.format == 'epub' %}
<span class="badge alert-info">{{ element.format }}</span>
{% endif %}
</td>
<td class="col-md-1 request-flag">
{% if element.publication.new_publication == True %}
<span class="glyphicon glyphicon-flag"></span>
{% else %}
<span></span>
{% endif %}
</td>
<td class="col-md-offset-5 col-md-3 text-right">{{ element.title }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
{% endfor %}
And in my views.py file :
def get_context_data(self, **kwargs):
search_category = Document.objects.values_list('publication__category__name', flat=True).distinct()
kwargs['search_category'] = search_category
search_format = Document.objects.values_list('format', flat=True).distinct()
kwargs['search_format'] = search_format
search_language = Document.objects.values_list('language', flat=True).distinct()
kwargs['search_language'] = search_language
checkbox_category = self.request.GET.getlist('CategoryChoice')
checkbox_format = self.request.GET.getlist('FormatChoice')
checkbox_language = self.request.GET.getlist('LanguageChoice')
choice_title = self.request.GET.get('TitleChoice')
kwargs['checkbox_category'] = checkbox_category
kwargs['checkbox_format'] = checkbox_format
kwargs['checkbox_language'] = checkbox_language
kwargs['choice_title'] = choice_title
# default to all documents
test_research = Document.objects.all().order_by('publication__category__name')
kwargs['test_research'] = test_research
if "SubmitChoice" in self.request.GET:
test_research = Document.objects.all()
# if user entered any search criteria, add those filters
if checkbox_category:
test_research = test_research.filter(publication__category__name__in=checkbox_category)
if checkbox_format:
test_research = test_research.filter(format__in=checkbox_format)
if checkbox_language:
test_research = test_research.filter(language__in=checkbox_language)
if choice_title:
test_research = test_research.filter(
Q(title__icontains=choice_title) | Q(publication__title__icontains=choice_title))
kwargs['test_research'] = test_research
return super(HomeView, self).get_context_data(**kwargs)
I can add models.py file if necessary. How it's possible to group them under the same category panel ?
EDIT :
I maybe found something with that :
{% for category in checkbox_category %}
<div class="col-sm-12">
<div class="panel panel-default request-panel">
<div class="panel-heading" role="tab">
<h4 class="panel-title">
{{ category }}
</h4>
</div>
{% for element in test_research %}
{{ element.publication.category }} - {{ category }}
{% if element.publication.category == category %}
But the if condition doesn't seems to work even if {{element.publication.category}} == {{category}}

You should restructure your data in the view so that it's already prepared for the template. Django's template system is built in a way to avoid this type of logic.
You might be able to do it simply like this:
from collections import defaultdict
research_categories = defaultdict(list)
for element in test_research:
research_categories[element.publication.category].append(element)
Then use research_categories in your template.

Related

Adding a tag to a pagination element django

When creating a pagination, everything works as it should. Added (?page= page number selection) pagination.
How can I add the pagination page number to its object?
When selecting an object and reloading the page, I need it to be spelled out in the URL (/?page=pagination number).
And the pagination remained on the selected page.
class MovieShow(DetailView):
model = Movie
template_name = 'movies/movie_play.html'
context_object_name = 'movie'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['object_list'] = Movie.objects.filter(course__slug=self.kwargs['course_slug'])
context['title'] = context['movie']
paginator = Paginator(context['object_list'], 1)
page = self.request.GET.get('page')
try:
context['object_list'] = paginator.page(page)
except PageNotAnInteger:
context['object_list'] = paginator.page(1)
except EmptyPage:
context['object_list'] = paginator.page(paginator.num_pages)
return context
This is how I present pagination in the template
<div class="pagination" id="pagination">
<span class="step-links" >
{% if object_list.has_previous %}
<a class="page-link" href="?page=1"> << </a>
<a class="page-link" href="?page={{ object_list.previous_page_number }}"> < </a>
{% endif %}
<span class="current">
{{ object_list.number }} из {{ object_list.paginator.num_pages }}
</span>
{% if object_list.has_next %}
<a class="page-link" href="?page={{ object_list.next_page_number }}"> > </a>
<a class="page-link" href="?page={{ object_list.paginator.num_pages }}"> >> </a>
{% endif %}
</span>
And so I have a search of the elements inside the pagination, on which I want to hang the pagination page number.
I really hope I asked the question correctly.
I will be glad of any help!
<div class="video_courses" id="block-posts">
{% for c in object_list %}
<a class="a_hover" href="{{ c.get_absolute_url }}">
<div class="video_courses_block">
<div class="video_courses_block_img"><img src="{{ c.poster.url }}" alt=""></div>
<div class="video_courses_block_text">
<div class="video_courses_block_text_title"><h2>[ {{ c.author }} ] {{ c.title }}</h2></div>
<div class="video_courses_block_text_navigation">
<div class="video_courses_block_text_left">{{ c.category }}</div>
<div class="video_courses_block_text_rig">{{ course.movie_set.count }}</div>
</div>
</div>
</div>
</a>
{% endfor %}
{% include 'pagination.html' %}
You just need to add if to the link and specify the page number
{% for c in object_list %}
{% if object_list.number %}
<a class="a_hover" href="{{ c.get_absolute_url }}?page={{ object_list.number }}">
{% endif %}
<div class="video_courses_block">
<div class="video_courses_block_img"><img src="{{ c.poster.url }}" alt=""></div>
<div class="video_courses_block_text">
<div class="video_courses_block_text_title">
<h2>[ {{ c.author }} ] {{ c.title }}</h2>
</div>
<div class="video_courses_block_text_navigation">
<div class="video_courses_block_text_left">{{ c.category }}</div>
<div class="video_courses_block_text_rig">{{ course.movie_set.count }}</div>
</div>
</div>
</div>
</a>
{% endfor %}
</div>
{% include 'pagination.html' %}

django NoReverseMatch at /account/dashboard/1/

I have a problem when I want to visit the user dashboard. On each article there is a link to the user profile, however, when I click on the link I'm getting NoReverseMatch. I was doing troubleshoots for days but I'm not able to fix the problem. Any help on how to fix this error is more than welcome, thank you!
article.html:
<h6> {{ article.author.profile.username}}</h6>
accounts>views:
#login_required
def guest_dashboard(request, pk):
user_other = User.objects.get(pk = pk)
already_followed = Follow.objects.filter(follower = request.user, following = user_other)
if guest_dashboard == request.user:
return HttpResponseRedirect(reverse('dashboard'))
return render(request, 'account/dashboard-guest.html', context = {'user_other' : user_other, 'already_followed' : already_followed})
articles>View:
def article_detail(request, pk):
article = Article.objects.get(pk=pk)
comment_form = CommentForm()
already_liked = Likes.objects.filter(article=article, user=request.user)
likesCounter = Likes.objects.filter(article=article).count()
if already_liked:
liked = True
else:
liked = False
if request.method == 'POST':
comment_form = CommentForm(request.POST)
if comment_form.is_valid():
comment = comment_form.save(commit=False)
comment.user = request.user
comment.article = article
comment.save()
return HttpResponseRedirect(reverse('article_detail', kwargs={'pk':pk}))
return render(request, 'article/single-article.html', context={'article':article, 'comment_form':comment_form, 'liked': liked,'likesCounter':likesCounter,'already_liked':already_liked})
article>URLs:
path('<pk>', article_detail , name = 'article_detail'),
account>URLs:
path('account/dashboard/', dashboard, name = 'dashboard'),
path('account/dashboard/<pk>/', guest_dashboard, name = 'guest_user'),
dashboard-guest.html>
{% extends 'base.html' %}
{% load static %}
{% block content %}
<!-- PROFILE CONTENT -->
<div id="profile-container">
<img class = "profile-cover-image" src = "/media/{{ user_other.profile.cover_picture }}">
<div class="profile-profile-image-cover">
<img class = "profile-profile-image-img" src = "/media/{{ user_other.profile.profile_picture }}">
</div>
<div class="edit-profile">
<div class="social-media-links">
<span><i class="fab fa-facebook-square fa-2x color-fb dec_none"></i></span>
<span><i class="fab fa-linkedin fa-2x color-linked dec_none"></i></span>
<span><i class="fab fa-twitter-square fa-2x color-twitter dec_none"></i></span>
</div>
</div>
<div class="profile-btns">
{% if not already_followed%}
Follow
{% else %}
Unfollow
{% endif%}
{% if user.post_author.all.count > 100 %}
<i class="fas fa-camera-retro fa-4x awards"></i>
{% endif %}
{% if user.article_author.all.count > 100 %}
<i class="fas fa-crown fa-4x awards"></i>
{% endif %}
</div>
</div>
<!-- END OF PROFILE CONTENT-->
<!-- PROFILE STAFF -->
<div class="profile-controllers">
<div class="profile-main-controller">
<div class="containerce">
<p class = 'boxce txt-center'><i class="fas fa-feather-alt fa-2x dcolor"></i>{{ user_other.article_author.all.count }}</p>
<p> Articles </p>
</div>
<div class="containerce">
<p class = 'boxce txt-center'><i class="fas fa-image fa-2x dcolor"></i> {{ user_other.post_author.all.count }}</p>
<p> Posts </p>
</div>
<div class="containerce">
<p class = 'boxce' txt-center><i class="fas fa-mask fa-2x dcolor"></i> {{ user_other.follower.count }}</p>
<p> Following </p>
</div>
<div class="containerce">
<p class = 'boxce txt-center'><i class="fas fa-hand-holding-heart fa-2x dcolor"></i> {{ user_other.following.count }} </p>
<p> Followers </p>
</div>
<div class="containerce">
{% if user_other.article_author.all.count and user_other.article_author.all.count > 100 %}
<p class = 'boxce txt-center'><i class="fas fa-award fa-2x dcolor"></i> 2</p>
{% else %}
<p class = 'boxce txt-center'><i class="fas fa-award fa-2x dcolor"></i> 0</p>
{% endif %}
<p> Awards </p>
</div>
</div>
</div>
<!-- MAIN FUNCTIONS -->
<div class="functions">
<div class="profile-buttons" id = "profile-buttons">
<a id = "btn_articles" href = "#" class = "btn-profile-buttons active">Articles </a>
<a id = "btn_posts" href = "#" class = "btn-profile-buttons ">Posts </a>
<a id = "btn_videos" href = "#" class = "btn-profile-buttons ">Videos</a>
</div>
<div class = "liner"></div>
</div>
<!-- POSTS -->
<div class="container-posts" id = "container_posts">
<!-- Original posts card-->
{% if user_other.post_author.all %}
{% for post in user_other.post_author.all %}
<div class="container-posts-card">
<a href = "{% url 'post_detail' pk=post.pk %}">
<img src = "{{ post.image.url}}" class = "container-post-card-img"> </a>
<div class="posts_card_edit">
<span class = "ellipsis-edit"><i class="fas fa-ellipsis-v"></i></span>
</div>
</div>
{% endfor %}
{% endif %}
<!-- END OF POST CARD-->
</div>
<!--ENDPOSTS-->
<!-- ARTICLES -->
<div class="container-articles" id = "container_articles">
{% if user_other.article_author.all %}
{% for user_other in user.article_author.all %}
<div class="container-article-card">
<a href = "{% url 'article_detail' pk=article.pk %}" class = "article-card-btn">
<img src = "{{ article.image.url }}" class = "container-article-card-img">
<div class="article-card-details">
<h6 class = "container-article-card-title">{{ article.title }}</h6>
<p class = "article-card-created">{{ article.publish_date }}</p>
</div></a>
<div class="container-article-card-edit">
<span class = "ellipsis-edit"><i class="fas fa-ellipsis-h"></i></span>
</div>
</div>
{% endfor %}
{% else %}
<div class="container-article-card">
<p>No Articles</p>
</div>
{% endif %}
</div>
<!-- ENDARTICLES-->
<!-- END OF MAIN FUNCTIONS -->
<br>
{% endblock %}
single-article.html
{% extends 'base.html' %}
{% load static %}
{% load humanize %}
{% load crispy_forms_tags %}
{% block content %}
<!-- CONTENT -->
<div id="container-single-post">
<div class="left-side">
<img class = "single-article-img" src = "{{ article.image.url }}">
<div class="single-post-author">
<img class = 'single-post-author-image' src = "{{ article.author.profile.profile_picture.url}}" style="object-fit:cover">
</div>
</div>
<div class="right-side">
<h6> {{ article.author.profile.username}}</h6>
{% if article.author.profile.full_name %}
<span span = "single-post-att">{{ article.author.profile.full_name}}</span>
{% else %}
<span span = "single-post-att"></span>
{% endif %}
<span span = "single-post-att">{{ article.category }}</span>
<span span = "single-post-att">{{ article.publish_date | naturaltime }}</span>
{%for a in already_liked %}
<div>{{a.user.profile.full_name}}, you are awesome!</div>
{% endfor %}
{% if not liked %}
<span class = "single-post-love" id="probaman"><i class="far fa-heart fa-2x"></i>{{likesCounter}}</span>
{% else %}
<span class = "single-post-love"><i class="fas fa-heart fa-2x"></i>{{likesCounter}}</span>
{% endif %}
</div>
<div class="single-post-content">
<h5>{{ article.title }}</h5>
<p>{{ article.content}}
</p>
</div>
<div class="single-post-comments">
<p>Comments</p>
<!-- Display Comment -->
{% for comment in article.article_comment.all %}
<div class="comment-single">
<div class="comment-author">
<img class = 'single-comment-author-image' src = "{{comment.user.profile.profile_picture.url}}" style="object-fit:cover">
<span class = 'comment-author'>{{comment.user.profile.full_name}}×</span>
</div>
<p class = "comment-date">{{comment.comment_date| naturaltime}}</p>
<div class="comment-author-content">
<p class = "comment-content">{{ comment.comment }}</p>
</div>
</div>
{% endfor %}
<!-- END Display Comment-->
<!-- POST COMMENT -->
<div class="col-lg-12">
<form method = "POST" class = "form-comment">
{{ comment_form | crispy }}
{% csrf_token %}
<button type ='submit' class = 'btn-default-comment'>Comment</button>
</form>
</div>
<!-- END POST COMMENT-->
</div>
</div>
<!-- END OF CONTENT-->
<br>
<br>
{% endblock %}
In the template, you have <a href = "{% url 'article_detail' pk=article.pk %}", but the variable article is not created anywhere. Where should it come from?
There is a loop {% for user_other in user.article_author.all %}, and it seems like it should somehow lead to an article, but that's unclear without the models and business logic knowledge. Should it be {% for article in user.article_author.all %} ?

Loop over Django objects and Bootstrap cards

I would like to use Bootstrap cards in order to create one card by object and add some sub_objects in each one.
For example :
I have an object Publication which could contain one or many sub_objects Document.
Publication object has some attributes : category, title, picture, description and Document object has some attributes like title, format, language, ...
I would like to get something like this :
For a same category, I create a card by publication and I list all documents for each publication.
This is what I get with my code :
As you can see, I should have document n°1 and document°2 in the same card and not two different cards.
This is my code :
{% for category in research_categories|dictsort:'name' %}
<div class="row">
<fieldset>
<legend id="category_{{ category.id }}"><span class="name">{{ category }}</span></legend>
</fieldset>
</div>
<div class="row">
<div class="col-sm-4">
{% for element in test_research %}
{% if element.publication.category|stringformat:"s" == category|stringformat:"s" %}
{% ifchanged %}
<div class="card" style="width:250px">
<img class="card-img-top" src="{{ element.publication.cover.url }}" alt="Card image">
<div class="card-body">
<h4 class="card-title">{{ element.publication }}</h4>
<table class="table table-condensed">
<tbody>
<tr>
<td> {{ element.title }}</td>
</tr>
</tbody>
</table>
</div>
</div>
{% endifchanged %}
{% endif %}
{% endfor %}
</div>
</div>
{% endfor %}
And my view according to this part is :
# By default, display documents
test_research = Document.objects.all().order_by('publication__title', 'title', 'language', 'format')
research_categories = defaultdict(list)
for element in test_research:
research_categories[element.publication.category].append(element)
research_publications = defaultdict(list)
for element in test_research:
research_publications[element.publication].append(element)
kwargs['test_research'] = test_research
kwargs['research_categories'] = research_categories
kwargs['research_publications'] = research_publications

Django template queryset.example_set.all() showing different primary key

{% for n in medrec %}
<tr>
<td>{{ n.patient.pk }}</td>
<td>{{ n.patient.name }}</td>
<td>
<div class="ui grid">
<form class="ui form" id="mform{{ n.id }}" action="/mbill/" method="post">
{% csrf_token %}
<input value="{{ n.pk }}" type="hidden" name="pk">
{% for m in n.med_set.all %}
<div class="row">
<div class="eight wide column">{{ m.medicine }}</div>
<div class="eight wide column">
<div class="field"><input name="{{ m.medicine.id }}" type="text"></div>
<h5>{{ m.medicine.quantity }} left</h5>
</div>
</div>
{% endfor %}
</form>
</div>
</td>
<td class="right aligned">
<button type="submit" class="ui button green" form="mform{{ n.id }}" id="mbill">bill</button>
</td>
</tr>
{% endfor %}
I am trying to access pk of foreign keys of medrec or n. but instead of real pk it show 1,2,3... every time
the n.medicine.id gives 1,2,3... instead of the real 3,4,5 is there a work around for this?
class Medicine(models.Model):
medicalrec = models.ForeignKey(MedicalRec,related_name='med_set')
medicine = models.ForeignKey(Stock,related_name='stock_set')
stockpk = models.IntegerField()
class MedicalRec(models.Model):
patient = models.ForeignKey(Patient)
date = models.DateField()
disease = models.TextField()
treatment = models.TextField()
billed = models.BooleanField()

Django post duplicates on page refresh

I have this view which adds replies to a topic:
#login_required
def post_reply(request, topic_id):
tform = PostForm()
topic = Topic.objects.get(pk=topic_id)
args = {}
if request.method == 'POST':
post = PostForm(request.POST)
if post.is_valid():
p = post.save(commit = False)
p.topic = topic
p.title = post.cleaned_data['title']
p.body = post.cleaned_data['body']
p.creator = request.user
p.user_ip = request.META['REMOTE_ADDR']
p.save()
tid = int(topic_id)
args['topic_id'] = tid
args['topic'] = topic
args['posts'] = Post.objects.filter(topic_id= topic_id).order_by('created')
return render_to_response("myforum/topic.html",args)
else:
args.update(csrf(request))
args['form'] = tform
args['topic'] = topic
return render_to_response('myforum/reply.html', args,
context_instance=RequestContext(request))
The problem is that when user refershes the page after posting a reply her reply is being duplicated. How to avoid this?
UPDATE:Here is the related template:
{% extends "base.html"%}
{% load static %}
{% block content%}
<div class="panel">
<div class="container">
<!-- Posts -->
<div class="col-md-12">
<h3>{{ topic.title }}</h3>
<table class="table table-striped">
<tr class="col-md-9"><td>{{ topic.description }}</td></tr>
<tr class="col-md-3"><div class="userpanel"><td>{{ topic.created }}</td></div></tr>
{% for post in posts %}
<tr class="col-md-12 userpanel"><td>{{ post.title }}</td></tr>
<tr class="">
<td>
<div class="col-md-9 userpanel">{{ post.body }} <br> {{ post.created }} </div>
</td>
<td>
<div class="col-md-3 userpanel">{{ post.creator }} <br> {{ post.created }} </div>
</td>
</tr>
{% endfor %}
</table>
<hr />
<!-- Next/Prev page links -->
{% if posts.object_list and posts.paginator.num_pages > 1 %}
<div class="pagination">
<span class="step-links">
{% if posts.has_previous %}
previous <<
{% endif %}
<span class="current">
Page {{ posts.number }} of {{ topics.paginator.num_pages }}
</span>
{% if posts.has_next %}
>> next
{% endif %}
</span>
</div>
{% endif %}
<a class="button" href="/forum/reply/{{topic.id}}"> Reply </a>
</div> <!-- End col-md-12 -->
</div> <!-- End container -->
</div>
{% endblock %}
Always - I repeat, always, redirect after a POST.
So instead of doing a return render_to_response("myforum/topic.html",args) when your form is valid, do a return HttpResponseRedirect(url_of_your_view) (https://docs.djangoproject.com/en/1.7/ref/request-response/#django.http.HttpResponseRedirect)
Update after OP's comments:
You should use reverse (https://docs.djangoproject.com/en/1.7/ref/urlresolvers/#reverse) to create the url to redirect to:
return HttpResponseRedirect(reverse('myforum.views.topic', args=[topic_id]))
Also, I recommend to name your views (and drop strings for defining them since they are deprecated), so change your urls.py line like this:
from myforum.views import topic
...
url(r'^topic/(\d+)/$', topic, name='view_topic'),
...
And then just do a reverse('view_topic', args=[topic_id]) to get the url of your view.