Django Template logic - django

So I am just now getting to grips with Django,
I want to something relatively straughtforward. I have a model thus:
class Article(models.Model):
id = models.IntegerField(primary_key=True)
volnumber = models.IntegerField(db_column='volNumber')
title = models.TextField()
keywords = models.TextField(blank=True)
start_page = models.IntegerField(null=True, blank=True)
end_page = models.IntegerField(null=True, blank=True)
author_1 = models.TextField(blank=True)
author_2 = models.TextField(blank=True)
author_3 = models.TextField(blank=True)
author_4 = models.TextField(blank=True)
author_5 = models.TextField(blank=True)
author_6 = models.TextField(blank=True)
author_7 = models.TextField(blank=True)
author_8 = models.TextField(blank=True)
author_9 = models.TextField(blank=True)
author_10 = models.TextField(blank=True)
in my view:
def index(request):
article_list = Article.objects.all()
volume_list = Volume.objects.all()
auth_list = ['author_1', 'author_2', 'author_3', 'author_4', 'author_5', 'author_6', 'author_7', 'author_8', 'author_9', 'author_10', ]
return render_to_response('index.html', {
'article_list': article_list,
'volume_list': volume_list,
'auth_list' : auth_list,
})
and I want to iterate over the first articles authors, as well as eliminating empty entries for the list in the template:
<ul class="articleList">
{% for article in article_list %}
<li>
{% for author in auth_list %}
<i>{{ article."author" }}</i>
{% endfor %}
{{ article.title }}{{ article }}
</li>
{% endfor %}
</ul>
obviously that doesn't work, and I'm not sure the template is the place for this logic, but I hope from this it is clear what I am trying to achieve.
Any assistance much appreciated.

I am not sure you want to design a list of authors that way. If you want multiple authors, consider using a new model for Author and then using a ManyToManyField in your Article class to link articles to authors. Then, you can loop through authors in your template like so:
{% for author in article.authors.all %}
<!-- blah blah -->
{% endfor %}
Here is the Author model:
class Author(models.Model):
first_name = models.TextField(...) # don't copy to ..., put whatever params you need
last_name = models.TextField(...)
and the adjusted Article model:
class Article(models.Model):
# add this line
authors = models.ManyToManyField(Author)
Now you do not need to return an auth_list in your view code.

If you don't want to change your data model (although I strongly advice you to follow #andrew-lee suggestion) you are not allowed to call-by-name attributes in the templates. You should do:
# in the view
return render_to_response('index.html', {
'article_list': article_list,
'volume_list': volume_list,
'auth_list' : [getattr(article, name) for name in auth_list],
})
# in the template
{% for author in auth_list %}
<i>{{ author }}</i>
{% endfor %}

Building on what has already been said, it makes the most sense to change your model, but if you want to keep it as-is and display a list of only the author fields which have been filled in, you might do this in the template:
<ul class="articleList">
{% for article in article_list %}
<li>
{% for author in auth_list %}
{% if author %}
<i>{{ author }}</i>
{% endif %}
{% endfor %}
{{ article.title }}{{ article }}
</li>
{% endfor %}
</ul>

Related

Not able to display in Template the foreign key using ListView

I'm trying to display a photographic session with all of it photos, so I have the session name in one model and I have the pictures in
another model linked by a foreign key. I'm not able to display it in
the HTML I'm not sure if I'm using the ListView get_context_data
correctly and I'm certainly sure the the html code is not correct but
I have not found how to do it.
views.py
class SessionPictures(generic.ListView):
model = PostSession
template_name = 'photoadmin/gallery.html'
def get_context_data(self, **kwargs):
context = super(SessionPictures, self).get_context_data(**kwargs)
context['picture'] = Images.objects.all()
return context
models.py
class PostSession(models.Model):
session_name = models.CharField(max_length=25)
created_date = models.DateTimeField(default=timezone.now)
def __str__(self):
return str(self.session_name)
class Images(models.Model):
name = models.ForeignKey(
PostSession, related_name='images', on_delete=models.CASCADE, null=True, blank=True)
picture = models.ImageField(upload_to='pictures')
html
{% extends 'base.html' %}
{% load static %}
{% block content %}
<h2>Images</h2>
<ul>
{% for session in object_list %}
<li>{{ session.session_name }}</li>
<ul>
<li>{{session.picture_set.all.url}}</li>
</ul>
{% endfor %}
</ul>
{% endblock %}
I'm expecting this:
Woods
picture1.url
picture2.url
picture3.url
Beach
Picture4.url
picture5.rul
As you already defined related_name="images" in Images model, so, session.images_set attribute won't work with PostSession.
class Images(models.Model):
name = models.ForeignKey(
PostSession,related_name='images', on_delete=models.CASCADE, null=True, blank=True)
Instead, use session.image.all in template(FYI: it returns a queryset, so you need to iterate through it to get the image object):
{% for session in object_list %}
<li>{{ session.session_name }}</li>
<ul>
{% for i in session.images.all %}
<li> i.picture.url </li>
{% endfor %}
</ul>
{% endfor %}
More information on reverse relation can be found in documentation.

How can I grab articles with the same tag, so within a template I can display those articles?

I'm new to Django, so thanks for any help.
I have an Article model, and I would like to display related/similar articles by assigning tags to each article.
I've tried making a function/filter in my views.py that inherits from self (that particular article) and filters out the articles with the same tag, but with no success.
from django.db import models
class Article(models.Model):
title = models.CharField(max_length=200, blank=True)
thumbnail = models.ImageField(max_length=200, blank=True)
tag = models.CharField(max_length=200, blank=True)
from .models import Article
class ArticleView(DetailView):
template_name = "article/article.html"
model = Article
def related_articles(self):
tagged = Article.objects.filter(tag=self.tag)
return tagged
{% if articles.objects.all %}
{% for article in article.objects.all|related_articles %}
<div>
<img src="{{ article.thumbnail.url }}">
<span>{{ article.title }}</span>
</div>
{% endfor %}
{% endif %}
So, whenever I try to use this filter I get no results.
I think the related_articles function should be on the model class.
from django.db import models
class Article(models.Model):
title = models.CharField(max_length=200, blank=True)
thumbnail = models.ImageField(max_length=200, blank=True)
tag = models.CharField(max_length=200, blank=True)
def related_articles(self):
tagged = Article.objects.filter(tag=self.tag).exclude(pk=self.pk)
Suppose your have a view like this:
def articles(request):
articles = Articles.objects.all()
context = dict(articles=articles)
return render(request, 'app/articles.html', context)
You could have a template like this:
{% if articles|length %}
{% for article in articles %}
<div>
<img src="{{ article.thumbnail.url }}">
<span>{{ article.title }}</span>
{% for related_article in article.related_articles %}
<span>{{ related_article.title }}</span>
{% endfor %}
</div>
{% endfor %}
{% endif %}

Nested querysets in Django

Having a bit of trouble getting my Django app to display how I'd like it. My model looks like this:
class City (models.Model):
city_name = models.CharField(max_length=100, unique=True)
def __str__(self):
return self.city_name
class Portfolio(models.Model):
portfolio_name = models.CharField(max_length=20, unique=True)
city = models.ForeignKey(City, db_constraint=False, on_delete=models.CASCADE)
def __str__(self):
return self.portfolio_name
class Property (models.Model):
portfolio = models.ForeignKey(Portfolio, db_constraint=False, on_delete=models.CASCADE)
prop_name = models.CharField(max_length=250, unique=True)
def __str__(self):
return self.prop_name
I want my template to display each City, and under each City have its Portfolios, and under each portfolio have its Properties. I'm a bit new to Django, coming from AngularJS where I could do it like this to throw filters in my loops(obviously doesn't work in Django, at least how I'm doing it):
<ul>
{% for city in all_cities %}
<li>
{{ city.city_name }}
<ul>
{% for portfolio in all_portfolios| portfolio.city = city %}
<li>
{{ portfolio.portfolio_name }}
<ul>
{% for property in portfolio.all_properties| property.portfolio = portfolio%}
<li>
{{ property.prop_name }}
</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
Any ideas? There is probably a simple solution that I just can't verbalize yet. The only thing I've found to do it like this is to create a custom queryset for each city, then for each portfolio, but there has to be a better way to do this.
Ignoring the fact that it is not database efficient to do this, the easiest way is to just make sure you are accessing the reversed Foreign Key relationships correctly.
Do something like this:
{% for city in all_cities %}
...blah blah blah
{% for portfolio in city.portfolio_set.all %}
... Blah blah
{% for property in portfolio.property_set.all %}
... More blah
And you should be good to go

Get Featured Image from different Model

I have 2 model objects, Business & BusinessImage as so, listed with views and index.html. I am trying to list the business's featured image, but it's not happening. I am getting the following error:
'QuerySet' object has no attribute 'businessimage_set'
How can I get the business featured image for a list?
Business
class Business(models.Model):
name = models.CharField("Name", max_length=70, default="Business Name")
slug = models.SlugField()
description = models.TextField("About", max_length=400)
category = models.ManyToManyField(Category, verbose_name="Categories", blank=True)
order = models.IntegerField("Order", default=0)
claimed = models.BooleanField("Claimed", default=False)
featured = models.BooleanField("Featured", default=False)
class Meta:
ordering = ['order']
verbose_name = "Business"
verbose_name_plural = "Businesses"
def __str__(self):
return self.name
BusinessImage
class BusinessImage(models.Model):
business = models.ForeignKey(Business)
image = models.ImageField(upload_to="images/business")
title = models.CharField(max_length=120)
featured = models.BooleanField(default=False)
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
updated = models.DateTimeField(auto_now_add=False, auto_now=True)
def __str__(self):
return self.title
view.py
from .models import Business, BusinessImage
def index_view(request):
latest_business_list = Business.objects.all()
images = latest_business_list.businessimage_set.all()
template = loader.get_template('index.html')
context = RequestContext(request, {
'latest_business_list': latest_business_list,
'images': images,
})
return HttpResponse(template.render(context))
index.html
{% block content %}
<div class="text-center business_title">
<h2>Featured</h2>
</div>
{% if latest_business_list %}
{% for business in latest_business_list|slice:":4" %}
{% if business.active %}
<div class="col-sm-6 col-md-3">
<li>{{ business.name }}</li>
{% for image in latest_business_list.businessimage_set.all %}
{% if image.featured %}
<a href="{% url 'single_product' product.slug %}">
<img src="{{MEDIA_URL}}{{image.image}}" alt="{{image}}">
</a>
{% endif %}
{% endfor %}
</div>
{% endif %}
{% endfor %}
{% endif %}
{% endblock %}
businessimage_set is an attribute of a Business instance, but you're trying to access it as an attribute of a queryset (i.e. list of businesses). If your goal is just to be able to access the images for each business in a template, you can leave out images entirely. Instead your template would have:
{% for image in business.businessimage_set.all %}
(Though look into prefetch_related for efficiency.)

Django model relationships in views and templates

I'm working on multi-user rss reader. I want to limit display of posts only to those which are unread. I've managed to do this in my single "feed" view as below, but I can't figure out how to do the same in multiple feed aka "category" view.
I've been trying something like here https://docs.djangoproject.com/en/1.5/topics/db/queries/#spanning-multi-valued-relationships but it didn't work for me
Should I change my "category" view code or template code? and if so how would you go about it?
thanks!
-S
models
class UserCategory(models.Model):
name = models.CharField(unique=False, max_length=64)
user = models.ForeignKey(User)
slug = AutoSlugField(populate_from='name', always_update='True', unique_with='user')
class Feed(models.Model):
feed_url = models.URLField(unique=True)
default_title = models.CharField(max_length=64, blank=True)
link = models.URLField(blank=True)
class UserFeed(models.Model):
feed = models.ForeignKey(Feed)
title = models.CharField(max_length=64)
category = models.ForeignKey(UserCategory)
user = models.ForeignKey(User)
slug = AutoSlugField(populate_from='title', always_update='True', unique_with='user')
class Post(models.Model):
feed = models.ForeignKey(Feed)
title = models.CharField(max_length=256)
content = models.TextField()
link = models.URLField(max_length=512)
class ReadPost(models.Model):
user = models.ForeignKey(User)
post = models.ForeignKey(Post)
views
def feed(request, user_feed_slug):
user_feed = get_object_or_404(UserFeed.objects.filter(slug=user_feed_slug, user=request.user))
read_post = ReadPost.objects.filter(user=request.user).values_list('post')
posts = Post.objects.select_related().filter(feed=user_feed.feed).exclude(id__in=read_post)
def category(request, user_category_slug):
user_category = get_object_or_404(UserCategory.objects.filter(slug=user_category_slug, user=request.user))
templates
feed
{% for post in posts %}
{{ post.title }}
{% endfor %}
category
{% for feed in user_category.userfeed_set.all %}
{{ feed.title }}
{% for post in feed.feed.post_set.all %}
{{ post.title }}
{{ post.content }}
{% endfor %}
{% endfor %}
You can write custom template filter, i.e:
#register.filter
def unread(posts, read_posts):
return posts.exclude(id__in=read_posts)
(before you must pass read_post to category template context).
Try this queryset:
def category(request, user_category_slug):
user_category = get_object_or_404(UserCategory, slug=user_category_slug,
user=request.user))
feeds = UserFeed.objects.filter(category__slug=user_category_slug, user=request.user)\
.prefetch_related('feed__post_set')
then in your template:
{% for feed in feeds %}
{{ feed.title }}
{% for post in feed.feed.post_set.all %}
{{ post.title }}
{{ post.content }}
{% endfor %}
{% endfor %}