django displaying posts and comments - python

this is models.py
class Post(models.Model):
author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
title = models.CharField(max_length=100)
content = models.TextField()
date = models.DateTimeField(default=timezone.now)
def write(self):
self.date = timezone.now()
self.save()
def __str__(self):
return self.title
class Comment(models.Model):
post = models.ForeignKey('humorge.post', on_delete=models.CASCADE, related_name='comments')
author = models.CharField(max_length=100)
content = models.TextField()
date = models.DateTimeField(default=timezone.now)
def add_coment(self):
self.date = timezone.now()
self.save()
def __str__(self):
return self.content
and this is views.py
def mainpage(request):
return render(request, 'index.html')
def post(request):
datas = Post.objects.order_by('-date')
comments = Comment.objects.all()
return render(request, 'post.html', {'datas': datas, 'comments': comments})
and this is template
{% extends 'layout.html' %}
{% block main %}
<div class="container">
{% for data in datas %}
<div class="row">
<div class="col s12 m7">
<div class="card">
<div class="card-image">
<img src="#">
<span class="card-title">{{ data.title }}</span>
</div>
<div class="card-content">
<p>{{ data.content }}</p>
</div>
<div class="card-action">
<p>{{ data.date }}</p>
</div>
<div class="card-action">
{% for comment in comments %}
{% if comment.post == data.title %}
{{ comment.date }}<br>
<strong>{{ comment.author }}</strong>
<p>{{ comment.content }}</p>
{% endif %}
{% empty %}
<p>There is no comments</p>
{% endfor %}
</div>
</div>
</div>
</div>
{% empty %}
<p>there is no posts</p>
{% endfor %}
</div>
{% endblock %}
I want to display posts and comments
when I try to have two posts and each post has one comments
it shows like each posts has two comments
so I added {% if comment.post == data.title %} in the template
but it shows nothing
I tried to find answers on google, youtube, some tutorial page....
but what I found was just how to add comments on posts..
or displaying post and comment but actually one post one comment

You don't need to query list of comments in you views, you need just posts:
def post(request):
datas = Post.objects.order_by('-date')
return render(request, 'post.html', {'datas': datas})
And in template you can then do something like this:
{% block main %}
<div class="container">
{% for data in datas %}
...
<div class="card-action">
{% for comment in data.comments.all %} // Gives list of all comments for the current post ie. data
{{ comment.date }}<br>
<strong>{{ comment.author }}</strong>
<p>{{ comment.content }}</p>
{% empty %}
<p>There is no comments</p>
{% endfor %}
</div>
{% empty %}
<p>there is no posts</p>
{% endfor %}
</div>
...
{% endblock %}
Btw the thing that's wrong with the if condition in your template is that you are doing {% if comment.post == data.title %} but commpent.post is an object of model Post and post.title is string, so they are never equal. What you need to do is {% if comment.post == data %} or {% if comment.post.title == data.title %}

In your post view, instead of:
comment = Comment.objects.all()
which will fetch all the comments irrespective of the post it belongs to,
do this:
comment = datas.comments.all()
where the 'comments' is the related_name declared in the post field of the Comment model.

Related

Django Please help me place a checkbox and a mail box with a send button on the html page

One of functionality in my training project:
subscribe to the news by check-box and e-mail.
Send newsletter daily.
The user can unsubscribe from the mailing list in his profile by unchecking the checkbox.
It so happened that first I set up a daily newsletter for users who have booleanfield = true.
For it I marked the checkboxes in the admin panel. It works.
Now it is necessary to add the checkbox and the mail field to the news page.
I'm stuck on the simplest. Tired and confused.
Please help me place a checkbox and a mail box with a send button on the news page
models.py
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
hr = models.BooleanField(default=False)
subscribed_for_mailings = models.BooleanField(default=False)
subscription_email = models.EmailField(default="")
def __str__(self):
return str(self.user)
Forms.py
class MailingForm(forms.ModelForm):
class Meta:
model = models.Profile
fields = ('subscription_email', 'subscribed_for_mailings', )
widgets = {
'subscription_email': forms.EmailInput(attrs={"placeholder": "Your Email..."}),
'subscribed_for_mailings': forms.CheckboxInput,
}
views.py
def all_news(request):
today = date.today()
today_news = models.TopNews.objects.filter(created__gte=today)
return render(request, "news.html",
{'today_news': today_news})
def mailing_news(request):
if request.method == 'POST':
mailing_form = forms.MailingForm(request.POST)
if mailing_form.is_valid():
mailing_form.save()
return HttpResponse('You will receive news by mail')
else:
mailing_form = forms.MailingForm()
return render(request, "news.html", {'mailing_form': mailing_form})
urls.py
...
path('news/', views.all_news, name='all_news'),
...
news.html
{% extends 'base.html' %}
{% block title %}
News
{% endblock %}
{% block body %}
<h1>Last news</h1>
{% for news in today_news%}
<h3>{{ news.title }}</h3>
Read this news
<p>
{{ news.created }}
</p>
<hr>
{% endfor %}
<h4>I want to receive news by mail</h4>
<form action="." method="post">
{{ mailing_form.as_p }}
{% csrf_token %}
<label>
<input type="submit" value="Subscribe">
</label>
</form>
{% endblock %}
The page displays a list of news and only the "send" button. There is no check-box and a field for mail
enter image description here
Finally I realized this functionality in a different way:
forms.py
class MailingForm(forms.ModelForm):
class Meta:
model = models.Profile
fields = ('subscribed_for_mailings', 'subscription_email', )
views.py
#login_required
def mailing_news(request):
if request.method == "POST":
mailing_form = forms.MailingForm(request.POST,
instance=request.user.profile,
)
if mailing_form.is_valid():
mailing_news = mailing_form.save(commit=False)
mailing_news.subscribed_for_mailings = mailing_news.subscribed_for_mailings
mailing_news.subscription_email = mailing_news.subscription_email
mailing_news.save()
return render(request, "subscribe_complete.html",
{"mailing_news": mailing_news})
else:
mailing_form = forms.MailingForm()
return render(request, 'subscribe.html', {"mailing_form": mailing_form})
news.html
{% extends 'base.html' %}
{% block title %}
News
{% endblock %}
{% block body %}
<h1>Last news</h1> {{ news.created }}
{% for news in today_news%}
<h3>{{ news.title }}</h3>
Read this news
<hr>
{% endfor %}
I want to receive news by mail
{% endblock %}
urls.py
...
path('subscribe/', views.mailing_news, name='subscribe')
...
news.html
{% extends 'base.html' %}
{% block title %}
News
{% endblock %}
{% block body %}
<h1>Last news</h1> {{ news.created }}
{% for news in today_news%}
<h3>{{ news.title }}</h3>
Read this news
<hr>
{% endfor %}
I want to receive news by mail
{% endblock %}
subscribe.html
{% extends 'base.html' %}
{% block title %}
Subscribe
{% endblock %}
{% block body %}
<form action="." method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ mailing_news.as_p }}
{% if user.profile.subscribed_for_mailings is True %}
<input type="checkbox" name="subscribed_for_mailings" id="id_subscribed_for_mailings" checked="">
If you don't want to receive emails anymore, uncheck
<br>
Subscription email: <input type="email" name="subscription_email" value={{ user.profile.subscription_email }} class="vTextField" maxlength="254" id="id_subscription_email">
{% else %}
<label>
<input type="checkbox" name="subscribed_for_mailings" id="id_subscribed_for_mailings">
I want to subscribe for mailing news
</label>
<p><label>
Send news on my email:
<input type="email" name="subscription_email" class="vTextField" maxlength="254" id="id_subscription_email">
</label></p>
{% endif %}
<p><input type="submit" value="Update"></p>
</form>
{% endblock %}
subscribe_complete.html
{% extends 'base.html' %}
{% block title %}
Subscribing complete
{% endblock %}
{% block body %}
<h3>Hi {{ user.username }}</h3>
Thanks for subscribing.
You will receive daily news by email: {{ user.profile.subscription_email }}
{% endblock %}
you need to change subscribed_for_mailings in mailing news, like this
def mailing_news(request):
if request.method == 'POST':
mailing_form = forms.MailingForm(request.POST)
if mailing_form.is_valid():
profile = mailing_form.save(commit=False) ####
profile.subscribed_for_mailings = mailing_form.cleaned_data.get('subscribed_for_mailings') ####
profile.subscription_email = mailing_form.cleaned_data.get('subscription_email') ####
profile.save() #### new_line
return HttpResponse('You will receive news by mail')
else:
mailing_form = forms.MailingForm()
return render(request, "news.html", {'mailing_form': mailing_form})
you can change in cleaned_data.get('....')

Comments in the admin panel are added, but they are not visible on the site

Based on this tutorial https://www.youtube.com/watch?v=An4hW4TjKhE&ab_channel=AbhishekVerma
I'm trying to add the ability to add comments under posts, add a comment in the admin panel, everything is ok, but the site does not display anything under the post
here is models.py
from django.db import models
from django.urls import reverse
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
class Post(models.Model):
published = None
title = models.CharField(max_length=200)
author = models.ForeignKey(
'auth.User',
on_delete=models.CASCADE,
)
body = models.TextField()
header_image = models.ImageField(blank=True, null=True, upload_to="images/", default='fox.jpeg')
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post_detail', args=[str(self.id)])
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='post_post')
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='user_user')
content = models.TextField(max_length=160)
timestamp = models.DateTimeField(auto_now_add=True)
def __str__(self):
return '{}-{}'.format(self.post.title, str(self.user.username))
views.py
from django.http import HttpResponseRedirect
from django.shortcuts import render, get_object_or_404
from django.views.generic import ListView, DetailView
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.urls import reverse_lazy
from .models import Post, Comment
from django import forms
from .forms import *
class BlogListView(ListView):
model = Post
template_name = 'home.html'
context_object_name = 'posts'
paginate_by = 2
queryset = Post.objects.all()
class BlogDetailView(DetailView):
model = Post
template_name = 'post_detail.html'
class BlogCreateView(CreateView):
model = Post
template_name = 'post_new.html'
fields = ['title', 'author', 'body', 'header_image']
class BlogUpdateView(UpdateView):
model = Post
template_name = 'post_edit.html'
fields = ['title', 'body', 'header_image']
class BlogDeleteView(DeleteView):
model = Post
template_name = 'post_delete.html'
success_url = reverse_lazy('home')
#property
def image_url(self):
"""
Return self.photo.url if self.photo is not None,
'url' exist and has a value, else, return None.
"""
if self.image:
return getattr(self.photo, 'url', None)
return None
def post_detail(request, id, slug):
post = get_object_or_404(Post, id=id, slug=slug)
comments = Comment.objects.filter(post=post).order_by('-id')
is_liked = False
if post.likes.filter(id=request.user.id).exists():
is_liked = True
if request.method == 'POST':
comment_form = CommentForm(request.POST or None)
if comment_form.is_valid():
content = request.POST.get('content')
comment = Comment.objects.create(post=post, user=request.user, content=content)
comment.save()
return HttpResponseRedirect(post.get_absolute_url())
else:
comment_form = CommentForm()
context = {
'post': post,
'is_liked': is_liked,
'total_likes': post.total_likes(),
'comments': comments,
'comment_form': comment_form,
}
return render(request, 'myblog/post_detail.html', context) #his "blog" = my "myblog"
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('content',)
post_detail.html
{% extends 'base.html' %}
{% block content %}
<div class="post-entry">
<h2>{{ post.title }}</h2>
<p>{{ post.body }}</p>
</div>
<p>+ Edit Blog Post</p>
<p>+ Delete Blog Post</p>
<img src="{{ post.header_image.url|default_if_none:'fox.jpeg' }}">
{{ post.body|urlize }}
{% for comm in post.commentpost_set.all%}
{{ comm.user }} <br>
{{ comm.text }} <br><br>
{% endfor %}
{% endblock content %}
<br><br>
<hr>
<form method="post">
{% csrf_token %}
{{ comment_form.as_p }}
{% if request.user.is_authenticated %}
<input type="submit" value="Submit" class="btn btn-outline-success">
{% else %}
<input type="submit" value="Submit" class="btn btn-outline-success" disabled>
{% endif %}
</form>
<div class="main-comment-section">
{{ comments.count }} Comment{{ comments|pluralize }}
{% for comment in comments %}
<blockquote class="blockquote">
<p class="mb-0">{{ comment.content }}</p>
<footer class="blockquote-footer">by <cite title="Source Title">{{ comment.user|capfirst }}</cite></footer>
</blockquote>
{% endfor %}
</div>
myblog/urls.py
from django.urls import path
from .views import (
BlogListView,
BlogDetailView,
BlogCreateView,
BlogUpdateView,
BlogDeleteView,
)
urlpatterns = [
path('post/new/', BlogCreateView.as_view(), name='post_new'),
path('post/<int:pk>/', BlogDetailView.as_view(), name='post_detail'),
path('post/<int:pk>/edit/',BlogUpdateView.as_view(), name='post_edit'),
path('post/<int:pk>/delete/',BlogDeleteView.as_view(), name='post_delete'),
path('', BlogListView.as_view(), name='home'),
]
base.html
{% load static %}
<html>
<head>
<title>Django blog</title>
<link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400"
rel="stylesheet">
<link href="{% static 'css/base.css' %}" rel="stylesheet">
</head>
<body>
<div>
<header>
<div class="nav-left">
<h1>Django blog</h1>
<h2>Admin</h2>
</div>
<div class="nav-right">
+ New Blog Post
</div>
</header>
{% if user.is_authenticated %}
<p>Hi {{ user.username }}!</p>
{% else %}
<p>You are not logged in.</p>
Log In<br>
<p>Sign up</p>
{% endif %}
{% block content %}
{% endblock content %}
</div>
</body>
</html>
<ul class="pagination">
{% if page_obj.has_previous %}
{% if page_obj.number|add:'-3' > 1 %}
<li class="pagination__item">
1
</li>
{% endif %}
{% if page_obj.number|add:'-3' >= 3 %}
<li class="pagination__item pagination__item--dots">
<a href="?{{ genre }}{{ year }}page={{ page_obj.previous_page_number|add:'-3' }}">
<span class="pagination__link">• • •</span>
</a>
</li>
{% endif %}
{% endif %}
{% if paginator.page_range|length > 1 %}
{% for i in paginator.page_range %}
{% if page_obj.number == i %}
<li class="pagination__item active">
<a class="pagination__link" href="#">{{ i }}</a>
</li>
{% elif i > page_obj.number|add:'-4' and i < page_obj.number|add:'4' %}
<li class="pagination__item">
<a class="pagination__link" href="?{{ genre }}{{ year }}page={{ i }}">{{ i }}</a>
</li>
{% endif %}
{% endfor %}
{% endif %}
{% if page_obj.has_next %}
{% if page_obj.number|add:'4' < page_obj.paginator.num_pages %}
<li class="pagination__item pagination__item--dots">
<a href="?{{ genre }}{{ year }}page={{ page_obj.next_page_number|add:'3' }}">
<span class="pagination__link">• • •</span>
</a>
</li>
{% endif %}
{% if page_obj.number|add:'3' < page_obj.paginator.num_pages %}
<li class="pagination__item">
<a class="pagination__link" href="?{{ genre }}{{ year }}page={{ page_obj.paginator.num_pages }}">
{{ page_obj.paginator.num_pages }}
</a>
</li>
{% endif %}
{% endif %}
</ul>
Thanks for any help
Your post_detail.html extends base.html, hence any content you wish to render must be inside some block and this block also must be present in the parent template (base.html here). You currently have some content outside any block and hence they aren't rendered. Put the HTML inside the block and it will show up:
{% extends 'base.html' %}
{% block content %}
<div class="post-entry">
<h2>{{ post.title }}</h2>
<p>{{ post.body }}</p>
</div>
<p>+ Edit Blog Post</p>
<p>+ Delete Blog Post</p>
<img src="{{ post.header_image.url|default_if_none:'fox.jpeg' }}">
{{ post.body|urlize }}
{% for comm in post.commentpost_set.all%}
{{ comm.user }} <br>
{{ comm.text }} <br><br>
{% endfor %}
<!-- put them inside the block -->
<br><br>
<hr>
<form method="post">
{% csrf_token %}
{{ comment_form.as_p }}
{% if request.user.is_authenticated %}
<input type="submit" value="Submit" class="btn btn-outline-success">
{% else %}
<input type="submit" value="Submit" class="btn btn-outline-success" disabled>
{% endif %}
</form>
<div class="main-comment-section">
{{ comments.count }} Comment{{ comments|pluralize }}
{% for comment in comments %}
<blockquote class="blockquote">
<p class="mb-0">{{ comment.content }}</p>
<footer class="blockquote-footer">by <cite title="Source Title">{{ comment.user|capfirst }}</cite></footer>
</blockquote>
{% endfor %}
</div>
{% endblock content %}

Trying to show model data on web page by using ListView. Its not working

I created the model post and I want to show all the posts on Web Page using Class-based views but It's not working. the URL is opening but the web page is not showing anything( stuff that is on homepage.html and on _post.html but navbar is there which is coming from _inject.html). The problem is in coding in the template.
Post Model-
class Post(models.Model):
auther = models.ForeignKey(User, related_name="posts",on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now=True)
heading = models.CharField(max_length=400)
message = models.TextField()
message_html = models.TextField(editable=False)
def __str__(self):
return self.message
def save(self,*args,**kwargs):
self.message_html = misaka.html(self.message)
super().save(*args,**kwargs)
def get_absolute_url(self):
return reverse('posts:single',kwargs={'username':self.user.username,'pk':self.pk})
class Meta:
ordering = ['-created_at']
unique_together = ['auther','message']
Post view-
class ListPosts(generic.ListView):
model = models.Post
template_name = "homepage.html"
homepage.html
{% extends "_inject.html" %}
{% block content %}
<div class="col-md-8">
{% if post.count == 0 %}
<h2>No posts in this group yet!</h2>
{% else %}
<ul>
{% for p in Post.all %}
<h1>p.message</h1>
<li> {% include "_post.html" %} </li>
{% endfor %}
</ul>
{% endif %}
</div>
{% endblock %}
_post.html-
<div class="media">
<h3 class="mr-5">#{{ post.user.username }}</h3>
<div class="media-body">
<strong>{{ p.user.username }}</strong>
<h5>{{ p.message_html|safe }}</h5>
<time class="time">{{ p.created_at }}</time>
<div class="media-footer">
{% if user.is_authenticated and post.user == user and not hide_delete %}
<a href="{% url 'posts:delete' pk=post.pk %}" title="delete" class="btn btn-simple">
<span class="fa fa-remove text-danger" aria-hidden="true"></span>
<span class="text-danger icon-label">Delete</span>
</a>
{% endif %}
</div>
</div>
</div>
Try changing your homepage.html to something like this:
{% extends "_inject.html" %}
{% block content %}
<div class="col-md-8">
{% if post_list %}
{% for post in post_list %}
<h1>{{post.message}}</h1>
<li>{% include "_post.html" %} </li>
{% endfor %}
{% else %}
<h2>No posts in this group yet!</h2>
{% endif %}
</div>
{% endblock %}

Django dynamic homepage

I have a lots of apps, but I want to generate all app's data on my homepage. Here's my apps:blog,members
I want to show blogs and my members on my homepage
I know that if I want to generate one app's data,I can do this:
blog/urls.py:
urlpatterns = [
url(r'^$', ListView.as_view(
queryset=Post.objects.all().order_by("-date")[:10],
template_name='blog1.html')),
and in blog1.html:
{% extends "index.html" %}
{% block blog %}
{% for post in blog_post %}
<div id="blog-wrapper" class="bgrid-third s-bgrid-half mob-bgrid-whole group">
<article class="bgrid">
<h5>{{ post.date }} </h5>
<h3><div class = "entry-title">{{ post.title }}</div></h3>
<p>{{ post.user }}</p>
<p><div class = "post_body">{{ post.body|safe|linebreaks }}</div></p>
</article>
</div>
{% endfor %}
{% endblock %}
{% block member %}
Here when I go to the url,I can see all blogs I write,but now I want to see blogs and members(another app) on one page, so how can I do this?
I would suggest you to use ListView's get_context_data method.
Create view in your project's views.py:
from django.views.generic import ListView
# Import your models here.
class HomepageView(ListView):
model = Post
ordering = '-date'
template_name = 'blog1.html'
context_object_name = 'posts'
def get_context_data(self, **kwargs):
context = super(HomepageView, self).get_context_data(**kwargs)
context['members'] = Member.objects.all()
return context
def get_queryset(self):
return super(HomepageView, self).get_queryset()[:10]
Then, change urls.py:
from django.conf.urls import url
# Import ``HomepageView`` here.
urlpatterns = [
url(r'^$', HomepageView.as_view(), name='homepage'),
# Other patterns here.
]
Now you can access posts using posts variable and members using members variable.
from .models import Post
from member.models import UserProfile
def get_data():
return {
"post": Post.objects.all().order_by("-date")[:10],
"user": UserProfile.objects.all()[:10]
}
then in my blog1.html:
{% extends "index.html" %}
{% block blog %}
{% for post in object_list.post %}
<div id="blog-wrapper" class="bgrid-third s-bgrid-half mob-bgrid-whole group">
<article class="bgrid">
<h5>{{ post.date }} </h5>
<h3><div class = "entry-title">{{ post.title }}</div></h3>
<p>{{ post.user }}</p>
<p><div class = "post_body">{{ post.body|safe|linebreaks }}</div></p>
</article>
</div>
{% endfor %}
{% endblock %}
{% block member %}
{% for post in object_list.user %}
<div class="bgrid member">
<div class="member-header">
<div class="member-pic">
<img src="{{ post.portrait }}" alt=""/>
</div>
<div class="member-name">
<h3>{{ post.user }}</h3>
<span>Creative Director</span>
</div>
</div>
<p>{{ post.intro }}</p>
<ul class="member-social">
<li><i class="fa fa-google-plus"></i></li>
<li><i class="fa fa-github"></i></li>
</ul>
</div> <!-- /member -->
{% endfor %}
{% endblock %}

Django-likes repeats the same post

I'm using the app django-likes and have managed to get it working. But I'm running into a very weird problem. The model "Story" is associated with the likes. Now the Story posts are repeated the number of votes they have -- for example, if they have 4 votes, they're actually repeated 4 times. Not sure what's going on. Any help much appreciated.
views.py
def home(request):
posts = Story.objects.all().order_by('votes')
form = StoryForm(request.POST or None)
if form.is_valid():
save_it = form.save(commit=False)
save_it.save()
messages.success(request, 'Thanks for adding your mix!')
return render_to_response('home.html',
locals(),
context_instance=RequestContext(request))
models.py
from django.db import models
import secretballot, likes
class Story(models.Model):
text = models.CharField(max_length=2000)
def __unicode__(self):
return self.text
secretballot.enable_voting_on(Story)
home.html
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% load likes_inclusion_tags %}
{% block content %}
{% if user.is_authenticated %}
<h1 align=center>Add Your Mix!</h1>
<div class='col-sm-6 col-sm-offset-3'>
<h1>{{ form_title }}</h1>
<form method="POST" action="" >{% csrf_token %}
{{ form|crispy }}
<input type='submit' class='btn' value='Add{{ button_submit }}' />
</form>
</div>
{% else %}
<h1 align=center>Login and add a story!</h1>
<p align=center><a class="btn btn-primary btn-lg" href="/accounts/login/" role="button">Login!</a></p>
{% endif %}
{% for post in posts %}
<p>{{ post.text }} {% likes post %}</p>
{% endfor %}
{% endblock %}
It is possible that the {% likes post %}returns a number and Multiplies the string {{ post.text }} five times like python would. Try separating it or converting it to string.

Categories