So my problem is that when I try to query to the image url so it can be posted to its corresponding Post all the images that have been uploaded to the media folder is being rendered, even though in the admin panel it shows that each post has it's own image and they are assigned to different posts, instead all of them are being rendered together for each and every post.
The models that I have are SellPost which is for creating a post and SellPostImage is for assigning the image to the post.
models.py
class SellPost(models.Model):
user = models.ForeignKey(User)
title = models.CharField(max_length=128)
category = models.ForeignKey(Category)
type = models.ForeignKey(SellPostType, default=None)
body = models.CharField(max_length=400)
price = models.DecimalField(decimal_places=1, max_digits=5, default=0.0)
views = models.IntegerField(default=0)
likes = models.IntegerField(default=0)
slug = models.SlugField(unique=True, default='automatic')
def save(self, *args, **kwargs):
self.slug = slugify(self.title)
super(SellPost, self).save(*args, **kwargs)
def __unicode__(self):
return self.title
class SellPostImage(models.Model):
user = models.ForeignKey(User, null=True)
post = models.ForeignKey(SellPost)
pictures = models.ImageField(upload_to='post_images', blank=True)
def __str__(self):
return "{}".format(self.post)
class Meta:
verbose_name_plural = "Post Images"
In the view I tried to create a context dict (because I'm a newbie in Django and have learned that from Tango with Django so I went with it) for the post and then the images:
views.py
def post(request, post_name_slug):
context_dict = {}
try:
post = SellPost.objects.get(slug=post_name_slug)
context_dict['post'] = post
post_image = SellPostImage.objects.all()
context_dict['post_image'] = post_image
except SellPost.DoesNotExist:
pass
return render(request, 'p.html', context_dict)
and here is how I tried to render them in the HTML file.
p.html
<ul>
{% for post in posts %}
<li>{{ post.title }} </li>
{% for post_images in post_image %}
<img style="width:200px; height:200px;" src="{{ post_images.pictures.url }}" />
{% endfor %}
{% endfor %}
</ul>
You'll want to filter the SellPostImage for the retrieved post:
post = SellPost.objects.get(slug=post_name_slug)
context_dict['post'] = post
post_image = SellPostImage.objects.filter(post=post)
context_dict['post_image'] = post_image
But you can just as easily put that logic part directly into your template:
{% for post in posts %}
<li>{{ post.title }} </li>
{% for post_images in post.sellpostimage_set.all %}
<img style="width:200px; height:200px;" src="{{ post_images.pictures.url }}" />
{% endfor %}
{% endfor %}
and then you can remove the SellPostImage in your views:
try:
post = SellPost.objects.get(slug=post_name_slug)
context_dict['post'] = post
except SellPost.DoesNotExist:
pass
In your post method you query for all SellPostImages:
post_image = SellPostImage.objects.all()
That's why you get all images for each post.
You can filter only the images associated with a post by doing the following instead:
post_image = SellPostImage.objects.filter(post=post)
It will provide all images for that specific post.
Related
I have a one-to-many relationship in Django as such:
class Listing(models.Model):
title = models.CharField(max_length=60)
class Images(models.Model):
listings = models.ForeignKey(Listing, on_delete=models.CASCADE)
image_urls = models.URLField(max_length = 200)
I have the following view defined:
from .models import Listing, Images
def index(request):
All_Listings = Listing.objects.filter(isActive=True)
return render(request, "index.html", {
"All_Listings": All_Listings,
"Images" : Images
})
Now for each listing I want to show all related images in my HTML. I have tried to do the following:
{% extends "layout.html" %}
{% block body %}
{% for listing in All_Listings %}
<h2>{{ list(Images.objects.filter(listings_id=2)) }}<h2>
{% endfor%}
{% endblock %}
(If this works, than later on I will replace 2 with listing.id)
This returns the following error:
Exception Type: TemplateSyntaxError
Exception Value: Could not parse the remainder: '(Images.objects.filter(listings_id=2))' from 'list(Images.objects.filter(listings_id=2))'
However, when I run this from the terminal it works:
>>> list(Images.objects.filter(listings_id=2))
[<Images: https://www.kettererkunst.com/still/kunst/pic570/531/422000352-4.jpg>, <Images: https://www.kettererkunst.com/still/kunst/pic570/531/422000352-1.jpg>]
How should I approach this?
You can create the #property image in the Listing class, and query all the related Images in it.
class Listing(models.Model):
title = models.CharField(max_length=60)
#property
def images(self):
return Images.objects.filter(listings=self)
class Images(models.Model):
listings = models.ForeignKey(Listing, on_delete=models.CASCADE)
image_urls = models.URLField(max_length = 200)
And then call listing.images in the template:
{% for listing in All_Listings %}
{%for image in listening.images%}
{{ image }}
{% endfor%}
{% endfor%}
I have a little problem with a query. I work on a blog website with django. For posts I have the first page where i display all the posts as a list, with their details (title, date posted etc.) and I want to display the number of comments for each post along with title, date posted and tags. I'm not sure how to make that, I need to implement something on the model classes or in view function that renders the page ?
Here are the model classes.
class Post(models.Model):
author = models.ForeignKey(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
title = models.CharField(max_length=500)
content = models.TextField()
tags = models.CharField(max_length=100)
date_posted = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.title
class Comment(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
comment_text = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
def __str__(self):
return f'{self.user.username} Comment ' + str(self.id)
and the view function
def blog(request):
context = {
'posts': Post.objects.all(),
'title': 'Blog',
'banner_page_title': 'Blog',
'page_location': 'Home / Blog'
}
return render(request, 'blog/blog.html', context)
Method 1:
You can use this in your template.
{% for post in posts %}
{{ post.comment_set.count }}
{% endfor %}
Method 2:
You can implement a model method like this:
class Post(models.Model):
....
def __str__(self):
return self.title
#property
def comment_count(self):
return self.comment_set.count()
And you can call the model method in your template like this:
{% for post in posts %}
{{ post.comment_count }}
{% endfor %}
Use a reverse lookup in the template and count to get the number of related objects:
{{ post.comment_set.count }}
Something like this?
template.html
...
{% for post in posts %}
<div> Title: {{post.title}} </div>
<div> Date Posted: {{post.date_posted}} </div>
<div> Number of Comments: {{post.comment_set.count}} </div>
{% endfor %}
I have a model where I am using two foreign keys. One of them is the logged-in user and the other is for inheriting the post. But post foreign key is not working or not saving into the database but it should save the particular post chosen by the user or with pk.
This is my models.py:
class Booking(models.Model):
b_price = models..ManyToManyField(price, related_name='b_price',on_delete=models.CASCADE,null=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, default='')
approved_price = models.BooleanField(default=False)
pay = models.CharField(max_length=30, default='')
mode = models.CharField(max_length=30 ,default='')
def __str__(self):
return str(self.user)
This is my views.py:
class booking_approve(CreateView, LoginRequiredMixin):
form_class = forms.booking_form
model = Booking
template_name = "confirm_booking.html"
success_url = reverse_lazy("Loader:post")
def form_valid(self, form):
booking = get_object_or_404(Booking, pk=self.kwargs.get('pk'))
print(form.cleaned_data)
bk = form.save(commit=False)
bk.user = self.request.user
bk.save()
bk.b_price.add(booking)
return super().form_valid(form)
This is my urls.py:
path('confirm_booking/<int:pk>/booking',views.booking_approve.as_view(), name="booking_approve"),
This is the HTML page where I pass the pk:
{% for loader_post in request.user.Loader.all %}
{% for price in loader_post.prices.all %}
{{loader_post.image_of_load.url }}
Post id : {{loader_post.id }}
Driver offer : {{price.driver_price }}
Offer by : {{price.driver_name }}
<a style="margin-right:20px;" href="{% url 'Loader:booking_remove' price.id %}"></a>
<
</div>
</div>
{% endfor %} {% endfor %} {% endblock content %}
This is my post pic. When I click on the tick button, the next form will appear but it should also take the id of the post but it won't.
This the pk's error:
I would like to create a simple forum with Python Django. The main thing I can not figure out is getting informations from two models.
I want to display: Post title, content, author, published date and signature. This is my post_detail.html
{% extends 'Homepage/base.html' %}
{% block content %}
<h1>{{ post.title }}</h1>
<h6>Kategoria: {{ post.category }} | Autor: {{ post.author }} | {{ post.published_date }}</h6>
<p>{{ post.description|linebreaksbr }}</p>
<p><hr>{{ HERE I DON'T KNOW HOW TO SHOW SIGNATURE }}</p>
{% endblock %}
</body>
</html>
Homepage app models.py
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
class Category(models.Model):
title = models.CharField(max_length=100)
description = models.TextField()
def __str__(self):
return self.title
class Post(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=100)
description = models.TextField()
category = models.ForeignKey(Category, on_delete=models.CASCADE)
published_date = models.DateTimeField(default=timezone.now)
updated = models.DateTimeField(blank=True, null=True)
views = models.IntegerField(default=0)
def __str__(self):
return self.title
accounts app models.py
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='user', on_delete=models.CASCADE)
website = models.URLField(default='', blank=True)
city = models.CharField(max_length=100, default='', blank=True)
signature = models.TextField(default='', blank=True)
def create_profile(sender, **kwargs):
user = kwargs["instance"]
if kwargs["created"]:
user_profile = UserProfile(user=user)
user_profile.save()
post_save.connect(create_profile, sender=User)
def __str__(self):
return self.user.username
My full code is on https://github.com/Incybro/Forum
You can just follow the relationships:
<p>{{ post.author.user.signature }}</p>
(Note, you've set the related_name from User to UserProfile to user, which makes no sense. You should leave it as the default, which would be userprofile.)
I guess your {{post.author}} won't be returning anything, change in to {{post.author.get_full_name}}
For signature, in your model you don't need to add any related name,
user = models.OneToOneField(User, on_delete=models.CASCADE)
in template,
{{post.author.userprofile.signature}}
Why not just return the relevant UserProfile model when you send the request?
def my_view(request):
context = {}
my_post = Post.objects.all.get(0) # get the post here
my_user = UserProfile.objects.get(user=my_post.author)
context['post'] = my_post
context['user'] = my_user
return TemplateResponse(request, 'my_template.html', context)
Then, in your html, you can use those template tags.
{% block content %}
<h1>{{ post.title }}</h1>
<h6>Kategoria: {{ post.category }} | Autor: {{ post.author }} | {{ post.published_date }}</h6>
{% autoescape on %}
<p>{{ post.description|linebreaksbr }}</p>
<p><hr>{{ user.signature }}</p>
{% endautoescape %}
{% endblock %}
You want the autoescape so people can't change the look or function of your site by injecting malicious HTML/JS into your site.
So far my blog project has :
Models.py
class Category(models.Model):
title = models.CharField(max_length=200)
def __str__(self):
return self.title
class Meta:
verbose_name_plural = "categories"
class Post(models.Model):
title = models.CharField(max_length=200)
summary = models.CharField(max_length=500, default = True)
body = models.TextField()
pub_date = models.DateTimeField(default=timezone.now)
categories = models.ForeignKey('Category', default=True)
def __str__(self):
return self.title
Views
from django.shortcuts import render
from .models import Post, Category
def getAllCategories(request):
categories = Category.objects.all()
context = {
'categories':categories,
}
return render(request, 'categories/getAllCategories.html', context)
Template
{% extends "../posts/base.html" %}
{% block content %}
<div>
{% for category in categories %}
<div>
<h3>{{ category.title }}</h3>
<ul>
{% for post in category.post_set.all %}
<li><a href=#>{{post.title}}</a></li>
- {{post.summary}}
{% endfor %}
</ul>
</div>
{% endfor %}
</div>
{% endblock %}
This pulls through all of my posts per category fine - however I'm stuck as I would like to only pull through the latest three posts per category. I understand that in a simple view you can use order_by()[:3], but then you can't use post_set with that. So I need a way of filtering by top three posts within a category, so using the many-to-many relationship. Hope this is clear.
Many thanks