Access ForeignKey set directly in template in Django - django

I have this simplified model:
class Item(models.Model):
name = models.CharField(max_length=120)
class ItemImage(models.Model):
image = models.ImageField(upload_to='upload_dir')
item = models.ForeignKey(Item)
An Item can have many ItemImages. I also have a template rendering the following data set from the view:
items = Item.objects.all()
So now I would want to do something like this in the template:
{% for item in items %}
<div>
{{ item.name }}<br>
<img src="{{ item.itemimage_set.all()[0] }}">
</div>
{% endfor %}
But obviously that's not possible. Not from the template directly, at least.
What is the proper way to get the equivalent of the first image inside the template?

{% with item.itemimage_set.all|first as image %}
<img src="{{ image.url }}" />
{% endwith %}

Or you could add a method to your Item model:
def get_first_image(self):
return self.itemimage_set.all()[0]
and then call this method in your template:
{{ item.get_first_image }}
Or you could use:
{{ item.itemimage_set.all.0 }}
and to get the first image's url:
<img src="{{ item.itemimage_set.all.0.url }}">
Though if you need more flexibility (more than one picture in certain cases, etc.) it's probably best to write a little templatetag.

One possible way would be to iterate over all the ItemImages like so:
{% for item in items %}
<div>
{{ item.name }}<br>
{% for image in item.itemimage_set.all %}
<img src="{{ image.image.url }}">
{% endfor %}
</div>
{% endfor %}

This worked for me, use the related_name in your models.
models.py
class Building(models.Model):
address = models.CharField(max_length=200, blank=True, null=True)
city = models.CharField(max_length=200, blank=True, null=True)
class Space(models.Model):
title = models.CharField(max_length=200, blank=True, null=True)
building = models.ForeignKey(Building, related_name="spaces_of_this_building")
buildings.html
{% for space in building.spaces_of_this_building.all %}
{{ space.title }}
{% endfor %}

If you want the first picture from set you can do:
{% for item in item.image_set.all %}
{{if forloop.first }}
<img src="{{ item.url }}">
{% endif %}
{% endfor %}
But i also love Andray solution with 'with'

Related

ValueError at / The 'pic' attribute has no file associated with it

I have a simple model with pic field having null and blank
class PostForNewsFeed(models.Model):
title = models.CharField(max_length=100, blank=True)
description = models.CharField(max_length=255, blank=True)
slug = models.SlugField(unique=True, max_length=100, blank=True)
pic = models.ImageField(upload_to='path/to/img', null=True, blank=True, default='')
{% if post.pic.url %}
<a href="{% url 'post-detail' post.id %}"
><img class="card-img-top" src="{{ post.pic.url }}" alt=""
/></a>
{% endif %}
When I submit without a pic I am getting the pic attribute not associated with a file.
My code seems fine in the template.
You should check if post.pic, not if post.pic.url:
{% if post.pic %}
<img class="card-img-top" src="{{ post.pic.url }}" alt=""/>
{% endif %}
Based on the discussion, in your template you use post.pic.url a lot of times when you work with template tags, etc. For example:
{% post_to_facebook post.pic.url "Post to Facebook" %}
you will need to make these conditional, since you can not fetch the .url of a post.pic if that post.pic is non existing.
You thus need to wrap this in an {% if … %} condition:
{% if post.pic %}
{% post_to_facebook post.pic.url "Post to Facebook" %}
{% endif %}

why i am not getting a followed_by(followers) entry showing up on my page

i am making a twitter like clone(just to learn how things works in django)
so i am basically trying to set up a many_to_many relationship.
i want to add the functionality of showing 'FOLLOWED_BY' and 'FOLLOWING' to a user profile but list of 'FOLLOWED_BY' is not showing on the page please someone help me!
in the models.py i have define two relationship
user = models.OneToOneField(settings.AUTH_USER_MODEL,
on_delete=models.SET_NULL, related_name='profile', null=True,
blank=True)
following = models.ManyToManyField(settings.AUTH_USER_MODEL,
related_name='followed_by', blank=True)
and in the user_detail.html i have the code for how a profile should look like
this is the models.py module:
from django.conf import settings
from django.db import models
# Create your models here.
class UserProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL,
on_delete=models.SET_NULL, related_name='profile',
null=True,
blank=True)
following = models.ManyToManyField(settings.AUTH_USER_MODEL,
related_name='followed_by', blank=True)
def __str__(self):
return str(self.following.all().count())
below is the code for user_detail.html file:
{% extends "base.html" %}
{% block content %}
<div class="row">
<div class="col-sm-3 col-xs-12" style="background-color: yellow">
<h1>{{ object.username }}</h1>
<p>Followers: {{ object.followed_by.count }}</p>
</div>
<div class="col-sm-9 col-xs-12">
<h1>Tweets</h1>
{% for tweet in object.tweet_set.all %}
{{ tweet }}<br/>
{% endfor %}
<hr/>
<h1>Following</h1>
{% for user in object.profile.following.all %}
<a href='/{{ user.username }}'>{{ user.username }}</a><br/>
{% empty %}
<h4>Not following any users</h4>
{% endfor %}
<hr/>
<h1>Followed By</h1>
{% for profile in object.profile.followed_by.all %}
<a href='/{{ profile.user.username }}'>{{ profile.user.username }}</a><br/>
{% empty %}
<h4>Not followed by any user</h4>
{% endfor %}
</div>
{% endblock content %}
for user profile i am getting the FOLLOWING field as i want but FOLLOWED_BY field is not showing how can i do that (what changes should i do in my code)??
You defined a following field that points to the user model, not to a Profile. As a result a Profile has no followed_by relation, a User object has.
I think it probably is better to let following point to Profile, like:
class UserProfile(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.SET_NULL,
related_name='profile',
null=True,
blank=True
)
following = models.ManyToManyField(
'self',
related_name='followed_by',
symmetrical=False,
blank=True
)
def __str__(self):
return str(self.following.all().count())
Then you can render this like:
<div class="col-sm-3 col-xs-12" style="background-color: yellow">
<h1>{{ object.username }}</h1>
<p>Followers: {{ object.followed_by.count }}</p>
</div>
<div class="col-sm-9 col-xs-12">
<h1>Tweets</h1>
{% for tweet in object.tweet_set.all %}
{{ tweet }}<br/>
{% endfor %}
<hr/>
<h1>Following</h1>
{% for profile in object.profile.following.all %}
<a href='/{{ profile.user.username }}'>{{ profile.user.username }}</a><br/>
{% empty %}
<h4>Not following any users</h4>
{% endfor %}
<hr/>
<h1>Followed By</h1>
{% for profile in object.profile.followed_by.all %}
<a href='/{{ profile.user.username }}'>{{ profile.user.username }}</a><br/>
{% empty %}
<h4>Not followed by any user</h4>
{% endfor %}
</div>
Your code has however some (serious) anti-patterns. The most important one is that you should not write business logic in the template. You should use the view for that. For example you can specify in the view a context like:
context = {
'tweets': object.tweet_set.all()
'followers': object.profile.following.select_related('user').all()
'followed_by': object.profile.followed_by.select_related('user').all()
}
We here can also use a .select_related() [Django-doc] that will boost performance significantly, since now all the users are fetched in the same query.
You also better use the {% url ... %} template tag [Django-doc] to construct queries. So instead of writing:
<a href="/{{ profile.user.username }}">
it is better to construct the query using a reverse lookup like:
<a href="/{% url 'profile_view' username=profile.user.username %}">

Django Image by Foreign Key and {% if / else %}

I trying to access the ImageField of a Model which is assigned via ForeignKey to another Model.
I have different Animal Apps in my Projects, with almost the same structure, like the following models.py. On the landingpage of My Project I want to display the last 3 entry of every (Species) Models with Name and Picture. If the Species has no Picture I would like to display the ImageField of the Farm, which is connected via ForeignKey to my species.
cows/models.py
class Farm(models.Model):
name = models.CharField(max_length=100)
farm_img = models.ImageField(upload_to='farm_images/',
max_length=255, null=True, blank=True)
class Cows(models.Model):
farm = models.ForeignKey(Farm, on_delete=models.CASCADE, null=True)
name = models.CharField(max_length=100)
entry_date = models.DateField(null=True, blank=True)
cow_img = models.ImageField(upload_to='farm_images/',
max_length=255, null=True, blank=True)
Views.py
class HomeIndex(TemplateView):
template_name = 'home.html'
def get_context_data(self, **kwargs):
context['chickens'] = Chicken.objects.order_by('-entry_date')[:3]
context['cows'] = Cows.objects.order_by('-entry_date')[:3]
context['cats'] = Cats.objects.order_by('-entry_date')[:3]
return context
home.html
<….>
{% for somecow in cows %}
<div class="col-3" id="p1">
<h2>{{ somecow.name }}</h2>
<h2>{{ somecow.entry_date }}</h2>
{% if somecow.cow_img %}
<img src="{{ somecow.cow_img.url }}" alt="Mod" height="100">
{% endif %}
</div>
{% endfor %}
<….>
Until here it worked.
But how can i access the FK.Model of the Model?
Or in other Words how can I tell Django:
“If you found no cow Picture in Cow.Model,then show a Farm picture from the assigned Farm.Model?”
As I understand I can access the assigned FK Models via
{% for something in MyModel1.MyModel2_set.all %}.
my approach for home.html
<….>
{% for somecow in cows %}
<div class="col-3" id="p1">
<h2>{{ somecow.name }}</h2>
<h2>{{ somecow.entry_date }}</h2>
{% if somecow.cow_img %}
<img src="{{ somecow.cow_img.url }}" alt="Mod" height="100">
{% else %}
{% for farm in somecow.farm_set.all %}
{% if farm.farm_img %}
<img src="{{ farm.farm_img.url }}" alt="Mod" height="100">
{% endif %}
{% endfor %}
{% endif %}
</div>
{% endfor %}
<….>
So far I received no error Message, but I also see no Farm Image. I am sure I mixed something up in home.html. On the other Side I think I maybe I missed something in my view, something like MyModel.objects.all()
I am thankful for every hint.
You're overcomplicating things. There is only a single farm per cow: you just need to access it directly.
{% else %}
{% if cow.farm.farm_img %}
<img src="{{ cow.farm.farm_img.url }}" alt="Mod" height="100">
{% endif %}
{% endif %}

Django many-to-many field in template and through

In my models there are some manytomany fields. I've been struggling to make them appear in the template. One is a regular ManyToMany field, the other one uses through. The problem is that the amount is not shown. I understand that currently the iteration is only defined for component in pcbuilds.components.all. How to manage the amount in there as well?
models.py:
class Component(models.Model):
name = models.CharField(max_length=100, unique=True,help_text='Component name')
manufacturer = models.IntegerField(blank=True,null=True,choices=MANUFACTURERS)
model = models.CharField(max_length=100,unique=True,blank=True,null=True, help_text='model')
class Tag(models.Model):
title = models.CharField(max_length=100,unique=True,blank=True,null=True, help_text='tagname')
class PCBuilds(models.Model):
title = models.CharField(max_length=50, help_text='PC build title')
components = models.ManyToManyField(Component,help_text='Pick your components from the list or create and add them.',through='Componentlist')
subtitle = models.CharField(blank=True,max_length=80, help_text='Subtitle')
def __str__(self):
return self.title
class Componentlist(models.Model):
component = models.ForeignKey(Component, on_delete=models.CASCADE,related_name='components')
pcbuild = models.ForeignKey(PCBuilds, on_delete=models.CASCADE,related_name='pcbuilds')
amount = models.FloatField(null=True,help_text='amount')
template:
<div class="card-deck">
{% for pcbuilds in object_list|slice:":3" %}
<div class="card" style="width: 18rem;">
<div class="card-header">
<a href="{% url 'pcbuilds_detail' pcbuilds.pk %}">
<span class="font-weight-bold">{{ pcbuilds.title }}</span></a> ·
<span class="text-muted">{{ pcbuilds.subtitle }}</span>
</div>
<div class="card-body">
<ul>
{% for component in pcbuilds.components.all %}
<li>{{ component.name}}{{ component.manufacturer}}{{ component.model }}{{ componentlist.amount }}</li>
{% endfor %}
</ul>
</div>
<div class="card-footer text-center text-muted">
{% for tag in recipe.tags.all %}
Tags: {{ tag.title }}
{% endfor %}
</div>
</div>
<br />
{% endfor %}
You don't define componentlist there, so the template will ignore it. Normally, you need to follow a relationship, as you did to get component in the first place. But this way there is no access to the through table, as you've already effectively gone past it to get the target table.
Instead you need to follow the relationship from pcbuild to the through table, and from there to the component:
{% for componentlist in pcbuilds.pcbuilds.all %}
<li>{{ componentlist.component.name}}{{ componentlist.component.manufacturer}}{{ componentlist.component.model }}{{ componentlist.amount }}</li>
{% endfor %}
Note, your related names in that through table are strange, which is why I had to use that confusing pcbuilds.pcbuilds.all. The reverse relationship from pcbuild to componentlist should be componentlist_set, which is the default; there shouldn't be any reason to change that.

filter in django 2.0

Hey I am writing app in django many blogs with many articles each but i dont know how to take artices which belongs to blog and write filter
My articles model
class Articles(models.Model):
title = models.CharField(max_length=150, verbose_name="Tytul")
content = models.TextField(verbose_name="Tekst")
published = models.DateTimeField(verbose_name="Data publikacji",auto_now=True)
image = models.FileField(upload_to="images",verbose_name="Obrazy",default=None)
blog = models.ForeignKey(Blogs,on_delete=models.CASCADE,null=True)
My blogs model
class Blogs(models.Model):
title = models.CharField(max_length=150, verbose_name="Tytul")
user = models.CharField(max_length=160, verbose_name="Uzytkownik")
blog.html
{% include 'base.html' %}
{% block blog %}
<h2>{{ blog.title }}</h2>
<div class="blog-info">
Tworca : {{ blog.user }}
</div>
{% block article %}
{% for a in article.blog_set.all %} <---- here
<div class="article">
Opublikowano : {{ a.published }}
</div>
<img src="{{ a.image.url }}" class="article-img">
<div class="article-intro">
<p>{{ a.content }}</p>
</div>
{% endfor %}
{% endblock %}
{% endblock %}
database