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

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 %}

Related

How to create a link in the Django website

I am working on the Django blog. I have created a url column in the admin post as follows.
however when I click the link in the page, the page jumps to the link which contains the localhost:8000 at the head of the url.
e.g. http://127.0.0.1:8000/Yahoo/www.yahoo.com
I made a link as Visit yahoo.com! however this is probably a wrong way to do it.
Can you please advise me how to fix this issue?
my class in model.py
class Post(models.Model):
title = models.CharField(max_length=200, unique=True)
slug = models.SlugField(max_length=200, unique=True)
author = models.ForeignKey(User, on_delete= models.CASCADE,related_name='blog_posts')
updated_on = models.DateTimeField(auto_now= True)
content = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
status = models.IntegerField(choices=STATUS, default=0)
url = models.CharField(max_length=200, unique=True, default='')
class Meta:
ordering = ['-created_on']
def __str__(self):
return self.title
my html
{% extends 'base.html' %} {% block content %}
<div class="container">
<div class="row">
<div class="col-md-8 card mb-4 mt-3 left top">
<div class="card-body">
<h1>{% block title %} {{ object.title }} {% endblock title %}</h1>
<p class=" text-muted">{{ post.author }} | {{ post.created_on }}</p>
<p class=" text-muted">{{ post.url }}</p>
Visit yahoo.com!
<p class="card-text ">{{ object.content | safe }}</p>
</div>
</div>
{% block sidebar %} {% include 'sidebar.html' %} {% endblock sidebar %}
</div>
</div>
{% endblock content %}
http://127.0.0.1:8000/Yahoo/www.yahoo.com
This implies that the link you indicated was made relative to your current path:
Visit yahoo.com!
Making it absolute by adding a prefix slash would not help either as that would still reference to your current running server
Visit yahoo.com!
http://127.0.0.1:8000/www.yahoo.com
If the post.url is external and outside your server, append a prefix of http:// or https://
Visit yahoo.com!

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 %}">

Reverse for 'profile_update' with arguments '(1,)' not found. Issue

I have a base url link to access a profile edtting screen but it seems to break my application.
Ive tried so many things that i am getting confused by the different views. I was able to get the form appearing previously but have somehow broken it.
from my base.html(if i remove this line the app start to work again). Im not sure about this user.id parameter im passing in this - is it needed?
<li class="nav-item">
<a class="nav-link" href="{% url 'accounts:profile_update' user.id %}">Edit Profile</a>
</li>
my urls file:
path('profile/edit/', views.ProfileCreate.as_view(), name='profile_update'),
my model:
class Profile(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='userprofile')
houseNumber = models.CharField(max_length=150, default='')
street = models.CharField(max_length=150, default='')
suberb = models.CharField(max_length=150, default='')
city = models.CharField(max_length=150, default='')
phone = models.CharField(max_length=150, default='')
def __unicode__(self):
return self.user.get_full_name()
def __str__(self):
return self.user
def get_absolute_url(self):
return reverse('account:profile', kwargs=[self.pk])
my form:
class ProfileForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(ProfileForm, self).__init__(*args, **kwargs)
class Meta:
model = Profile
fields = ['user', 'houseNumber', 'street', 'suberb', 'city', 'phone']
the html for the form:
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-danger">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endfor %}
{% for error in form.non_field_errors %}
<div class="alert alert-danger">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endif %}
<div class="container">
<form enctype="multipart/form-data" action="{% url 'accounts:profile_update' %}" method="post" novalidate>
{% csrf_token %}
{{ form|crispy }}
<input name="Submit" type="submit" class="btn btn-success" value="Save"></input>
</form>
<p></p>
</div>
{% endblock %}
Apologies if this question is similar to a few others Ive asked but i just had to restart with this form using a different approach because it just wasnt working properly previously.
According to you url, you don't need to pass user.id through update_profile. So please change the code to:
<a class="nav-link" href="{% url 'accounts:profile_update' %}">Edit Profile</a>

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 %}

Access ForeignKey set directly in template in 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'