Django - show all images assigned to the post - python

I am creating blog application and I would like to show all images which were uploaded to the single blog post.
Here are my Models.py:
class Post(models.Model):
title = models.CharField(max_length=100)
content = RichTextField(blank=True, null=True)
class PostImage(models.Model):
post = models.ForeignKey(Post, default=None, on_delete=models.CASCADE, related_name='postimages')
image = models.ImageField(upload_to='gallery/')
Views.py
class PostGalleryView(DetailView):
model = Post
template_name = 'blog/gallery.html'
context_object_name = 'photos'
In the template if I put there {{ photos.postimages }} then it shows on the page: blog.PostImage.None
even though that 2 images are uploaded to the particular blog post. {{ photos.postimages.count }} shows number 2. If I tried to loop through photos.postimages it throws an error: 'RelatedManager' object is not iterable. Any idea how I can access the PostImage model in the template?

Try using loop in your template with all like:
{% for photo in photos.postimages.all %}
{{ photo.image }}
{% endfor %}

Related

Django show same content (of a model) in sidebar of every page (also in different apps)

I have two apps: blog and mysite.
In the project folder, I have a template which includes a sidebar template. This sidebar is shown on every page of the project (index pages, mysite pages, blog pages).
One part of this sidebar should show a list of the latest x blog entries (independent of the page where the user is).
blog/models.py
class Post(models.Model):
author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
title = models.CharField(max_length=264)
text = RichTextField(config_name='detail_text_field', default='')
created_date = models.DateTimeField(default=timezone.now)
blog/views.py
class LatestBlogEntriesListView(ListView):
model = Post
template_name = 'blog/_latest_blog_entries_list.html'
def get_queryset(self):
return Post.objects.all().order_by('created_date')[-3:]
sidebar.html
<div class="row">
{% include 'blog/_latest_blog_entries_list.html' %}
</div>
_latest_blog_entries_list.html
<h4>Latest Blog Entries</h4>
{% for post in objects %}
{{ post.title }}
{% endfor %}
Unfortunately, this does not work. My sidebar only shows the h4 "Latest Blog Entries", but not the posts. How can I do this?
Any help is highly appreciated!
I found to use a context processor, as described in this post: https://dev.to/harveyhalwin/using-context-processor-in-django-to-create-dynamic-footer-45k4
This allows to access a context variable within all pages.
When using ListView the default object is called object_list. Try changing your code to this:
{% for post in object_list %}
{{ post.title }}
{% endfor %}
You can also change this variable name in the view, so that when you catch it on the template, it's a custom name.
class LatestBlogEntriesListView(ListView):
model = Post
template_name = 'blog/_latest_blog_entries_list.html'
context_object_name = "your_new_object_name"

How do i query for comment in Django

I am new in Django and I have been following tutorials online. I am having problem on how to display the comments.
How do i query for comments in views, so i can display comments for a particular post.
Model:
class Post(models.Model):
poster_profile = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE, blank=True,null=True)
image_caption = models.TextField(blank=True, null=True)
class Comments (models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE, blank=True,null=True)
commented_image = models.ForeignKey(Post, on_delete=models.CASCADE, null=True, blank=True)
comment_post = models.TextField()
Views.py:
def home_view(request):
comment = Comments.objects.all() #This is getting all comment in all post, how do i query for comment in a particular post.
context{'comment':comment}
return render(...)
Template:
{% for com in comment %}
<p>{{ com.comment_post }}</p>
{% endfor %}
You can do
post = Post.objects.get(id=1)
comment = post.comments_set.all()
Following Relationships "Backward"
If a model has a ForeignKey, instances of the foreign-key model will have access to a Manager that returns all instances of the first model. By default, this Manager is named FOO_set, where FOO is the source model name, lowercased. This Manager returns QuerySets, which can be filtered and manipulated as described in the “Retrieving objects” section above.
Note this behaviour can be overridden.
You can override the FOO_set name by setting the related_name parameter in the ForeignKey definition. For example, if the Entry model was altered to blog = ForeignKey(Blog, on_delete=models.CASCADE, related_name='entries'), the above example code would look like this:
Edit #2:
views.py:
def home_view(request):
posts = Post.objects.all().reverse()[5]
context{ 'posts': posts, }
return render(...)
Now in your templates you can do something like:
{% if posts %}
{% for post in posts %}
{{ post.image_caption }}
{% for comment in post.comments_set.all %}
{{ comment.comment_post }}
{% endfor %}
{% endfor %}
{% endif %}
First of all, take a look at Django queryset documentation, especially select_related for this kind of issues (to reduce number of queries to database). I didn't try but following snippet must work.
class Post(models.Model):
poster_profile = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE)
image_caption = models.TextField(blank=True, null=True)
class Comments (models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE)
commented_image = models.ForeignKey(Post, related_nam="comments", on_delete=models.CASCADE)
comment_post = models.TextField()
...
def home_view(request):
post = Post.objects.filter(id=request.data.get('post_id')).select_related("comments") # specify the post anyhow ..
comments = post.comments
context{'comment': comments}
return render(...)
def home_view(request):
particular_Post= Post.objects.get(id=1)
comment = Comments.objects.get(Post=particular_Post)
context{'comment':comment}
return render(...)
to understund Query in django i suggest U to start by
python manage.py shell
and Import you're Models

List of posts not displaying - django

I have created a post model and would like to view the posts in post_list. While creating the new post, it is redirecting to post_list but not displaying any post.
Also, in my post_form I have rendered the fields manually by using django templates. I couldnt figure out where I have made the mistake. Can someone please help me out. Thanks
models.py
class Post(models.Model):
author = models.ForeignKey(User, on_delete = models.CASCADE)
slug = models.SlugField(unique=True, blank=True, default=uuid.uuid1)
By default the context_object_name is object_list
Either you access your Posts list in template with object_list
{% for post in object_list %}
{{ post }} <!-- with lowercase -->
{% endfor %}
Or you change the context_object_name to post_list, so that way you will be able to access the post list with post_list in template
class PostListView(ListView):
model = Post
context_object_name = 'post_list'
You probably need to use lowercase variable name in your post_list.html.
For instance, {{ Post.title }} should probably be lowercase {{ post.title }}.
There are a few places to change that.

How to create a form field for every foreignkey in manytomany relationship in Django

I don't understand how to build a specific form in Django.
First of all here are my models:
class Category(models.Model):
name = models.CharField(max_length=200, unique=True)
class Assessment(models.Model):
name = models.CharField(max_length=200)
pub_date = models.DateTimeField(verbose_name=_('date published'), default=timezone.now)
classgroup = models.ForeignKey(ClassGroup, verbose_name=_('class'), on_delete=models.CASCADE, related_name='+')
category = models.ManyToManyField(Category, through='AssessmentScale', through_fields=('assessment', 'category'),)
total = models.IntegerField()
class AssessmentScale(models.Model):
assessment = models.ForeignKey(Assessment, on_delete=models.CASCADE)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
value = models.IntegerField()
I would like to have a form like this html form. Actually, an assessment scale is sub-divided into different categories. So when I create an assessment, I'd like have a form field for each category allowing to add a value via my custom intermediary model AssessmentScale. But I really don't know the Django way to build this form. I read this post, which is similar I think, and someone advised the use of Inline model formsets. But I don't understand how to solve my problem with the latter. Could you help me?
I had no answer from Stackoverflow but a friend of mine solved my problem like this with inline formset:
# forms.py
class AssessmentForm(ModelForm):
class Meta:
model = Assessment
exclude = ('category',)
CategoryAssessmentFormSet = inlineformset_factory(
Assessment,
Assessment.category.through,
fields=['category', 'value'],
can_delete=False,
extra=Category.objects.count(),
max_num=Category.objects.count(),
widgets={'category': Select(attrs={'hidden': 'true'})}
)
in my view, to render the formset:
# views.py
initial = [{'category': category} for category in Category.objects.all()]
formset = CategoryAssessmentFormSet(initial=initial)
Select is hidden but I still want the name of the selected field, in my template:
# template
{{ formset.management_form }}
{% for form in formset %}
<div class="p-2">
{% for value,selected in form.fields.category.choices %}
{% if value == form.category.value %}{{ selected }}{% endif %}
{% endfor %}
{{ form.category }}
</div>
<div>
{{ form.value}}
</div>
{% endfor %}

Check if a user has voted on a Post, in the template

Here's my Post model:
models
class Post(models.Model):
user = models.ForeignKey(User, blank=True, null=True)
title = models.TextField(max_length=76)
content = models.TextField(null=True, blank=True)
...
class PostScore(models.Model):
user = models.ForeignKey(User, blank=True, null=True)
post = models.ForeignKey(Post, related_name='score')
upvotes = models.IntegerField(default=0)
downvotes = models.IntegerField(default=0)
And here's my template. I want to do something like this... if the user has upvoted or downvoted the Post, then hide the upvote/downvote buttons:
{% if request.user in Post.has_answered %}
{% else %}
<img src="upvote.png" class="upvote" />
<img src="downvote.png" class="downvote" />
{% endif %}
I planned to do this by adding a ManyToManyField called has_answered to my Post model, but i'm unable to do that as I get this error:
post.Post.has_answered: (fields.E304) Reverse accessor for 'Post.has_answered' clashes with reverse accessor for 'Post.user'.
HINT: Add or change a related_name argument to the definition for 'Post.has_answered' or 'Post.user'.
post.Post.user: (fields.E304) Reverse accessor for 'Post.user' clashes with reverse accessor for 'Post.has_answered'.
HINT: Add or change a related_name argument to the definition for 'Post.user' or 'Post.has_answered'.
Any idea how I can fix this? I'm not too sure about the error message as I don't think I can alter my current user field.
You can change your models to like this. You might not need PostScore model.
class Post(models.Model):
# Other Fields i.e title, content, author ...
upvotes = models.ManyToMany(User)
downvotes = models.ManyToMany(User)
You can get upvotes on a Post using this.
upvotes = post_object.upvotes.count()
downvotes = post_object.downvotes.count()
To see whether user has upvoted or not,
if request.user in post_object.upvotes.all():
# This user has upvoted this post
Same for downvotes.
You can do similar thing in your template as well and hide/show buttons based on condition.
{% if request.user in post_object.upvotes.all %}
<!-- show upvote button highlighted -->
{% elif request.user in post_object.downvotes.all %}
<!-- show downvote button highlighted -->
{% else %}
<!-- Show both buttons (not highlighted) -->
{% endif %}
Hope this helps.
Have you tried send the flag from your django views to template like :
def myView(request):
parameters['is_user_voted'] = PostScore.objects.filter(user=self.request.user).exists()
.....
.....
send ```parameters``` to your template using render()
And change you template as:
{% if is_user_voted == 'True' %}
{% else %}
<img src="upvote.png" class="upvote" />
<img src="downvote.png" class="downvote" />
{% endif %}

Categories

Resources