Here are my two models
class Category(models.Model):
name = models.CharField(max_length = 50)
description = models.CharField(max_length = 1000)
created = models.DateTimeField(auto_now_add=True)
def __unicode__(self, ):
return self.name
class Post(models.Model):
subject = models.CharField(max_length=50, blank=True)
description = models.CharField(max_length=1000)
created = models.DateTimeField(auto_now_add=True)
category = models.ManyToManyField(Category)
def __unicode__(self, ):
return self.subject
I'm displaying the subject, description, and date of each post in a template. But I also want to display the respective category for each post as well.
Here's the part of my view
def index(request):
posts = Post.objects.order_by("-created")
return render(request,'posts/index.html', {'posts':posts})
and then how I'm trying to display it in a template:
{% for post in posts %}
<div>
{{ post.subject }}<br />
{{ post.description }}<br />
{{ post.created }} | of {{ post.category }}
</div>
{% endfor %}
But the category will not show up, all I get is
<django.db.models.fields.related.ManyRelatedManager object at 0x7ff7e40a0c90>
I've tried doing post.category.name and other random combinations but it either gives nothing or a parsing error. I have no idea how to get the category displayed.
That's a Manager. Use it as you would any other Manager (e.g. Post.objects).
{% for category in post.category.all %}
Related
I have a list of reviews and each review has a rating average. My problem is trying to added each review id to the filter for the query result. For this, I assume a for loop in the filter is best.
I've found a previous post with a similar situation, but the same result doesn't seem to be working for me.
When I load my reviews page, I receive a TypeError: 'function' object is not iterable.
Here is my view.py file with the queries.
def reviews(request):
context = {
'reviews': Employee.objects.all(),
'rating': Employee.objects.filter(id__in=[review.id for review in reviews]).aggregate(rate=Avg(F('value1')+F('value2')+F('value3').....+F('valueN'))/N)
}
return render(request, 'reviews/reviews.html', context)
Reviews.html template.
{% extends "reviews/layout.html" %}
{% block content %}
{% for review in reviews %}
{% for rating in ratings %}
<article class="media content-section">
<img class="rounded-circle article-img" src="{{ review.author.profile.image.url }}">
<div class="media-body">
<div class="article-metadata">
<h4 class="mr-2">{{ review.company }} {{rating}}</h4>
<small class="text-muted">{{ review.date_posted|date:"F d, Y" }}</small>
</div>
<h5><a class="article-title" href="{% url 'review-detail' review.id %}">{{ review.title }}</a></h5>
<p class="article-content">{{ review.content }}</p>
</div>
</article>
{% endfor %}
{% endfor %}
{% endblock content %}
Any suggestions are much appreciated.
EDIT: Here is my model for the Employee table.
class Employee(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
company = models.CharField(max_length=100)
recommend = models.BooleanField(default=False)
salary = models.CharField(max_length=100)
salary_satis = models.CharField(max_length=100)
culture = models.CharField(max_length=100)
location = models.CharField(max_length=100)
work_env = models.CharField(max_length=100)
communication = models.CharField(max_length=100)
opportunity = models.CharField(max_length=100) # Opportunity happiness
leadership_satis = models.CharField(max_length=100)
fair_treatment = models.CharField(max_length=100)
advice = models.TextField() # Advice for management
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
ordering = ['-date_posted']
def __str__(self):
return f'{self.title, self.content, self.company, self.recommend, self.salary, self.salary_satis, self.culture, self.location, self.work_env, self.communication, self.opportunity, self.leadership_satis, self.fair_treatment, self.advice, self.date_posted, self.author}'
def get_absolute_url(self):
# Returns user to reviews page after their review has been submitted.
return reverse('reviews')
Your reviews in the dictionary, refers to the reviews view function (here both in boldface):
def reviews(request):
context = {
'reviews': Employee.objects.all(),
'rating': Employee.objects.filter(
id__in=[review.id for review in reviews]
).aggregate(
rate=Avg(F('value1')+F('value2')+F('value3').....+F('valueN'))/N
)
}
return render(request, 'reviews/reviews.html', context)
Indeed, you can not iterate over this function, since it has no __iter__ method attached to it, but even if it had, this is not what you want to do.
I think the most elegant way to solve this, is simply defining a reviews variable:
def reviews(request):
reviews = Employee.objects.all()
context = {
'reviews': reviews,
'rating': Employee.objects.filter(
id__in=[review.id for review in reviews]
).aggregate(
rate=Avg(F('value1')+F('value2')+F('value3').....+F('valueN'))/N
)
}
return render(request, 'reviews/reviews.html', context)
So now reviews is a local variable that you can acces, and since a queryseet is iterable, we can iterate over this.
That being said, it is a bit odd to use an id__in here, since reviews has all the Employees.
I have two models in my blog app:
class Tag(models.Model):
tag_name = models.CharField(max_length=20,
null=True)
def __str__(self):
return self.tag_name
class Post(models.Model):
tag = models.ManyToManyField(Tag, related_name="blog_tag",
blank=True)
In views i have:
tags = Tag.objects.all()
And
post = get_object_or_404(Post,
status="published",
publish__year=year,
publish__month=month,
publish__day=day,
slug=post)
So my question is - how can i filter tags by post ? I mean that i want to show only tags what i add to my post. I tried to do than in template , but something dosen't work :
{% for tag in tags %}
{% if tag in post %}
<div>
{{ tag.tag_name }}
</div>
{% endif %}
{% endfor %}
Post model:
class Post(models.Model):
STATUS_CHOICES = (
("draft", "Draft"),
("published", "Published"),
)
title = models.CharField(max_length=250)
slug = models.SlugField(max_length=250,
unique_for_date="publish")
author = models.ForeignKey(User,
related_name="blog_posts",
on_delete=models.CASCADE)
tag = models.ManyToManyField(Tag, related_name="blog_tag",
blank=True)
body = models.TextField()
publish = models.DateTimeField(default=timezone.now)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
status = models.CharField(max_length=10,
choices=STATUS_CHOICES,
default="draft")
image = models.ImageField(upload_to="blog/%Y/%m/%d",
blank=True)
class Meta:
ordering = ("-publish",)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("blog:post_detail",
args=[self.publish.year,
self.publish.strftime("%m"),
self.publish.strftime("%d"),
self.slug])
The answer is:
{% for tag in post.tag.all %}
<div class="fa fa-plus-square">
{{ tag.tag_name }}
</div>
{% endfor %}
Since you're using a ManyToManyField in the Post class, it would be clearer if that field was called tags rather than tag, since it is referring to more than one thing.
class Post(models.Model):
tags = models.ManyToManyField(Tag, related_name="blog_tag",
blank=True)
So once you have looked up a post with:
post = get_object_or_404(Post,
status="published",
publish__year=year,
publish__month=month,
publish__day=day,
slug=post)
You pass it to the template with:
return render(request, 'post_detail.html', {'post': post})
And then in the post_detail.html you can render the tags associated with the post:
{% for tag in post.tags.all %}
<div>
{{ tag.tag_name }}
</div>
{% endfor %}
No need to explicitly filter the tags as the ManyToManyField handles that for you.
You can do this :
{%for tag in tags %}
{% if tag.id == post.tag.id%}
<div>
{{ tag.tag_name }}
</div>
{%endif%}
{%endfor%}
I am creating a demo Django website where you browse Billy Joel's albums . You click on an album to view all songs.
(If it happens to be on: http://104.131.200.120/albums/all/--there's hardly any data at the moment. Only one song in Cold Spring Harbor, none in An Innocent Man)
I can't figure out how to display the song name in the album page. It can tell if there is a song, because Cold Spring Harbor prints out an empty "name/description" line, and An Innocent Man doesn't.
Here's the view
def album(request, album_id=1):
album = Album.objects.get(id=album_id)
album_songs = AlbumSong.objects.filter(id=album_id)
print(str(album_songs))
return render_to_response("album.html",
{"album": album, "album_songs" : album_songs})
(the print results in [<AlbumSong: Cold Spring Harbor: 10: Got To Begin Again>] being written to the console, when Cold Spring Harbor is selected.)
The model (note that the Song and Album models are not linked by foreign key. There's an intermediate table, AlbumSong):
from django.db import models
from django.contrib.auth.models import User
from time import time
def get_upload_file_name(instance, filename):
return "uploaded_files/%s_%s" % (str(time()).replace(".", "_"), filename)
class Album(models.Model):
title = models.CharField(max_length=70)
pub_date = models.DateField('release date')
is_official = models.BooleanField(default=False)
is_concert = models.BooleanField(default=False)
likes = models.IntegerField(default=0)
thumbnail = models.FileField(upload_to=get_upload_file_name, blank=True, null=True)
def __str__(self):
return self.title
class Song(models.Model):
name = models.CharField(max_length=100)
sub_name = models.CharField(max_length=200, null=True, blank=True)
length_seconds = models.IntegerField()
lyrics_url = models.TextField(default="", blank=True, null=True)
def __str__(self):
return self.name
class AlbumSong(models.Model):
song_id = models.ForeignKey(Song)
album_id = models.ForeignKey(Album)
sequence_num = models.IntegerField()
class Meta:
unique_together = ('album_id', 'sequence_num',)
unique_together = ('album_id', 'song_id',)
def __str__(self):
return str(self.album_id) + ": " + str(self.sequence_num) + ": " + str(self.song_id)
class FavoriteSongs(models.Model):
user_id = models.ForeignKey(User)
song_id = models.ForeignKey(Song)
sequence_num = models.IntegerField()
class Meta:
unique_together = ('user_id', 'song_id',)
unique_together = ('user_id', 'sequence_num',)
def __str__(self):
return "user=" + str(self.user_id) + ", song=" + str(self.song_id) + ", number=" + str(self.sequence_num)
class FavoriteAlbums(models.Model):
user_id = models.ForeignKey(User)
album_id = models.ForeignKey(Album)
sequence_num = models.IntegerField()
class Meta:
unique_together = ('user_id', 'album_id',)
unique_together = ('user_id', 'sequence_num',)
def __str__(self):
return "user=" + str(self.user_id) + ", album=" + str(self.album_id) + ", number=" + str(self.sequence_num)
and template:
{% extends "base.html" %}
{% block title %}Album detail{% endblock %}
<!-- <div id="sidebar"> -->
{% block sidebar %}
<UL>
<LI>Albums</LI>
</UL>
{% endblock %}
<!-- </div> -->
{% block content %}
<H1>{{ album.title }}</H1>
<P>{{ album.body }}</P>
{% if album.thumbnail %}
<P><img src="/static/{{ album.thumbnail }}" width="200"/></P>
{% endif %}
<P><UL>
<LI>Released: {{ album.pub_date }}</LI>
<LI>Official: {{ album.is_official }}</LI>
<LI>Concert: {{ album.is_concert }}</LI>
</UL></P>
<H2>Songs</H2>
{% for album_song in album_songs %} <!-- No colon after "album_songs" -->
<div>
<P><UL>
<LI>Name: {{ album_song.song.name }}<UL>
<LI>Description: {{ album_song.song.sub_name }}</LI>
</UL></LI>
</UL></P>
</div>
{% endfor %}
<P>Like this album -- {{ album.likes }} people liked this album.</P>
{% endblock %}
How do I display the song name in the template? What should album_song.song.name be changed to?
Thank you.
The problem is your field names. For some reason, you've called your foreign keys from AlbumSong "song_id" and "album_id". So you should use the same names in the template: {{ album_song.song_id.name }}.
However, it doesn't make sense to use this name. The Django field does not represent an ID, it represents the actual Song object. Django already creates an underlying database field with an "_id" suffix, so in this case it's created one called "song_id_id", which is silly. Rename your fields "song" and "album", and keep your template the way it is.
I have a model which I want to display as a Detail view, I have created a list view that has a link that leads to its detailed view. I dont get any errors but the template doesn't render any of the models detail
Link to DetailView
<a href="../ancillaries/{{ Ancillary.id }}" > Product </a>
Model
from django.db import models
from django.core.urlresolvers import reverse
class Ancillary(models.Model):
product_code = models.CharField(max_length=60, null=True)
type = models.CharField(max_length=120, null=True)
product = models.CharField(max_length=120, null=True)
standard = models.CharField(max_length=120, null=True)
measurement = models.CharField(max_length=120, null=True)
brand = models.CharField(max_length=120, null=True)
class Meta:
verbose_name_plural = "Ancillaries"
def get_absolute_url(self):
return reverse('ancillaries')
def __unicode__(self):
return u'%s %s %s %s %s %s %s' % (self.id, self.product_code, self.type,
self.product, self.standard,
self.measurement, self.brand)
View
class AncillaryDetail(DetailView):
model = Ancillary
def get_context_data(self, **kwargs):
context = super(AncillaryDetail, self).get_context_data(**kwargs)
context['ancillary_list'] = Ancillary.objects.all()
return context
Urls
url(r'^ancillaries/(?P<pk>\d+)/', AncillaryDetail.as_view(template_name='ancillary-detail.html')),
Template
{% for ancillary_list in object_list %}
{{ Ancillary.product}}
{{ Ancillary.type }}
{{ Ancillary.brand }}
{{ Ancillary.measurement }}
{% endfor %}
It looks as though you've used the documentation but adapted the ListView example incorrectly. If you want to display a single model instance then the DetailView is the correct view.
As #mrkre suggested you should name your URL pattern (although I would use the singular form for the name).
url(r'^ancillaries/(?P<pk>\d+)/', AncillaryDetail.as_view(
template_name='ancillary-detail.html'), name="ancillary_detail")
The view is then simply
class AncillaryDetail(DetailView):
model = Ancillary
In the template ancillary-detail.html you access the model instance using the default name object.
{{ object.product}}
{{ object.type }}
{{ object.brand }}
{{ object.measurement }}
Try:
{% for ancillary in ancillary_list %}
{{ ancillary.product}}
{{ ancillary.type }}
{{ ancillary.brand }}
{{ ancillary.measurement }}
{% endfor %}
I would suggest using names for url:
url(r'^ancillaries/(?P<pk>\d+)/', AncillaryDetail.as_view(), name="ancillary_details")
<a href="{% url 'ancillary_details' pk=ancillary.pk %}">
Place this right after your DetailView
template_name='ancillary-detail.html'
I have a blog app and i want to show each post in a very different way using classes and showing/not-showing parts, based in a foreign key value "postype".
This is my code:
{% for post in posts.object_list %}
<div class="{{ post.postype }}">
<h4>{{ post.title }}</h4>
{% if post.postype == 'Post' %}<p>{{ post.created }}</p>{% endif %}
</div>
{% endfor %}
And the result of that is:
<div class="Post">
Title Post One
</div>
<div class="News">
Title Post Two
</div>
<div class="Post">
Title Post Three
</div>
So my question is, why the "post.created" is not showing even though the div class shows "Post" in two cases?, which means the if should match.
This is the model i'm using
class Postype(models.Model):
postype = models.CharField(max_length=32)
def __unicode__(self):
return self.postype
class Post(models.Model):
author = models.ForeignKey(User)
postype = models.ForeignKey(Postype)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
title = models.CharField(max_length=100)
slug = models.SlugField()
text = models.TextField()
allow_comments = models.BooleanField(db_index=True, default=True)
published = models.BooleanField(db_index=True, default=True)
objects = PostManager()
def __unicode__(self):
return u"%s - %s" % (self.title, self.created)
def save(self, *args, **kwargs):
self.slug = slughifi(self.title)
super(Post, self).save(*args, **kwargs)
Thanks
If post.posttype is a foreign key to another model, you need to specify what attribute of posttype you want to compare against
so if
class PostType(models.Model):
name = models.CharField(...)
you should have
{% if post.posttype.name == "Post" %}...{% endif %}
As it stands you are comparing an object (posttype) to a string ("Post") which will always fail.
The reason the div shows the class "Post" correctly, is because django is automatically guessing how to display the Post model when you don't specify a field. To change the way a post is printed when no attribute is given, you can overwrite the unicode method of the model:
class PostType(models.Model):
name = models.CharField(...)
def __unicode__(self):
return self.name
This means that when you reference this post type (like in your question as ) the unicode method is called which returns self.name
Have you tried double quotes instead of single quotes in the if statement?