I created model Post and Comment, now I want to display comments from Post but I have a problem. In tutorial there is a line of code in html {% for comment in post.comments.all %} but isn't working in my app. If I set {% for comment in comments %} it works but displays all comments from models (I want only comments from the post). How to fix that? Below I pasted my code.
models.py
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=64, blank=False, null=False)
short_text = models.TextField(blank=False, null=False)
text = models.TextField(blank=False, null=False)
image = models.TextField(blank=False, null=False)
date = models.DateTimeField(auto_now_add=True, blank=True)
views = models.IntegerField(default=0)
class Comment(models.Model):
post = models.ForeignKey('main.Post', on_delete=models.CASCADE)
author = models.CharField(max_length=200)
text = models.TextField()
created_date = models.DateTimeField(auto_now_add=True, blank=True)
approved_comment = models.BooleanField(default=False)
def approve(self):
self.approved_comment = True
self.save()
def __str__(self):
return self.text
views.py
from django.shortcuts import get_object_or_404, render, redirect
from .models import Post, Comment
def index_pl(request):
posts = Post.objects.all()
return render(request, 'index_pl.html', {'posts': posts})
def single_article_pl(request, id):
posts = get_object_or_404(Post, pk=id)
posts.views = posts.views + 1
posts.save()
comments = Comment.objects.all()
return render(request, 'single_article_pl.html', {'posts': posts, 'comments': comments})
html
{% for comment in post.comments.all %}
<div class="comment">
<div class="date">{{ comment.created_date }}</div>
<strong>{{ comment.author }}</strong>
<p>{{ comment.text|linebreaks }}</p>
</div>
{% empty %}
<p>No comments here yet :(</p>
{% endfor %}
admin.py
from django.contrib import admin
from .models import Post, Comment
admin.site.register(Post)
admin.site.register(Comment)
In tutorial there is a line of code in html {% for comment in post.comments.all %} but isn't working in my app.
This is likely because they specified the related_name=… parameter [Django-doc] in the ForeignKey from Comment to Post, like:
# Option 1: set the related_name to 'comments'
class Comment(models.Model):
post = models.ForeignKey(
'main.Post',
related_name='comments',
on_delete=models.CASCADE
)
# …
The related_name=… specifies the name of the relation in reverse, so in this case accessing the Comments of a given Post object. By default this is model_name_set, so in this case comment_set.
You thus can either specify a related name; or you can acces the comment_set manager:
Option 2: use the default related_name
{% for comment in post.comment_set.all %}
<div class="comment">
<div class="date">{{ comment.created_date }}</div>
<strong>{{ comment.author }}</strong>
<p>{{ comment.text|linebreaks }}</p>
</div>
{% empty %}
<p>No comments here yet :(</p>
{% endfor %}
Related
Please let me know that where i am making mistake?
views.py
class AddComment(LoginRequiredMixin, CreateView):
model = Comment
form_class = CommentForm
template_name = 'comment.html'
success_url = reverse_lazy('home')
def form_valid(self, form):
form.instance.name = self.request.user
form.instance.post_id = self.kwargs\['pk'\]
return super().form_valid(form)
Are these forms written correctly?
forms.py
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('body', )
widgets = {
# 'name': forms.TextInput(attrs={'class': 'form-control'}),
'body': forms.Textarea(attrs={'class': 'form-control'}),
}
Should I make any changes in models?
models.py
class Comment(models.Model):
post = models.ForeignKey(Post,
related_name='comments',
on_delete=models.CASCADE)
name = models.ForeignKey(
User,
on_delete=models.CASCADE,
)
body = models.TextField(max_length=240)
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
return '%s - %s' % (self.post.title, self.name)
This is comment section for letting user to comment on post with showing its own name?
comments.html
{% if not object.comments.all %}
<p>No comments yet...</p>
Add one
{% else %}
Add Comment
<br><br>
{% for comment in object.comments.all %}
<strong>{{ comment.name }} </strong> - <small>{{ comment.date_added }}</small>
<br>
{{ comment.body }}
<br><br>
<hr>
{% endfor %}
{% endif %}
Here is the urls of AddComment class view.
urls.py
path('post/<int:pk>/comment/', AddComment.as_view(), name='comment'),][1]
You did not state clearly what has gone wrong with your code. I would like to give some suggestions. First of all,
{% for comment in object.comments.all %}
...
{% endfor %}
You are putting this block of code inside {% if not object.comments.all %}...{% endif %} so it will not show on template if the comment section is not empty.
Also, this link:
Add Comment
should open a Django template form, where user can actually fill in the comment. After that, on POST request of the form, it will send comment data to the URL you put in action param of the form, as below:
<form action="{% url 'comment' post.pk %}" method="post">
[Comment code here]
</form>
which will link to this URL you provided:
path('post/<int:pk>/comment/', AddComment.as_view(), name='comment'),]
It will be better if you can provide your code in views.py as well to make it easier to track down where it goes wrong.
I'm trying to learn Python Django with book "Example_Build_powerful_and_reliable_Python_web_applications" by Antonio Mele.
Really sorry for probably stupid questions, but i'm very new.
And sorry for my English, it isn't my native language.
Have some problem with one of the example from the book.
Do the same things as in the book, but URL's dont work.
MODELS.PY
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
from django.urls import reverse
class PublishedManager(models.Manager):
def get_queryset(self):
return super(PublishedManager, self).get_queryset().filter(status='published')
class Post(models.Model):
STATUS_CHOICES = (
('draft', 'draft'),
('published', 'published')
)
title = models.CharField(max_length=250)
slug = models.SlugField(max_length=250,
unique_for_date='publish')
body = models.TextField()
publish = models.DateTimeField(default=timezone.now)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
status = models.CharField(max_length=10,
choices=STATUS_CHOICES,
default='draft')
objects = models.Manager()
published = PublishedManager()
class Meta:
ordering = ('-publish',)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('blog:post_detail',
args=[self.publish.year,
self.publish.month,
self.day, self.slug])
VIEWS.PY
from django.shortcuts import render, get_object_or_404
from .models import Post
def post_list(request):
posts = Post.published.all
return render(request,
'blog/post/list.html',
{'posts': posts})
def post_detail(request, post):
post = get_object_or_404(Post, slug = post)
return render(request, 'blog/post/detail.html', {'post': post})
URLS.PY
from django.urls import path
from . import views
app_name ='blog'
urlpatterns = [
path('', views.post_list, name='post_list'),
path('<int:year>/<int:month>/<int:day>/<slug:post>/',
views.post_detail,
name='post_detail'),
]
BASE.HTML
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>{% block title %} {% endblock %}</title>
</head>
<body>
<div id="content">
{% block content %}
{% endblock %}
</div>
<div id="sidebar">
<h2>My Blog</h2>
<p>This is my blog</p>
</div>
</body>
</html>
LIST.HTML
{% extends "blog/base.html" %}
{% block title %}My blog{% endblock%}
{% block content %}
<h1>My Blog</h1>
{% for post in posts %}
<h2>
<a href="{{ post.get_absolute_url }}">
{{post.title}}
</a>
</h2>
<p class="date">
Published {{ post.publish }} by {{ post.author }}
</p>
{{ post.body|truncatewords:30|linebreaks }}
{% endfor %}
{% endblock %}
DETAIL.HTML
{% extends "blog/base.html" %}
{% block title %} {{ post.title }} {% endblock %}
{% block content %}
<h1> {{ post.title }} </h1>
<p class = "date">
Published {{ post.publish }} by {{ post.author }}
</p>
{{ post.body|linebreaks }}
{% endblock %}
Also add my urls to URLS here:
enter image description here
The problem is: when i click on posts on the page BASE.HTML i dont see correct URL and nothing is happening:
enter image description here
Really break my brain.
Thanks in advance for help.
Your VIEWS.py should contain the methods post(self,request) OR get(self,request) to be callable from the rendered HTML. The methods post_list(..) OR post_detail(..) are not callable on the Django framework.
Oh my f...ng god.
If somebody will face with the same problem..
In MODELS.PY just need to move Class Meta and 2 defs:
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
from django.urls import reverse
class PublishedManager(models.Manager):
def get_queryset(self):
return super(PublishedManager, self).get_queryset().filter(status='published')
class Post(models.Model):
STATUS_CHOICES = (
('draft', 'draft'),
('published', 'published')
)
title = models.CharField(max_length=250)
slug = models.SlugField(max_length=250,
unique_for_date='publish')
body = models.TextField()
publish = models.DateTimeField(default=timezone.now)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
status = models.CharField(max_length=10,
choices=STATUS_CHOICES,
default='draft')
objects = models.Manager()
published = PublishedManager()
class Meta:
ordering = ('-publish',)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('blog:post_detail',
args=[self.publish.year,
self.publish.month,
self.day, self.slug])
And then in will work good.
Very stupid mistake, so hard to find this..
I am trying to ad a condition into an html model in Django (python) and it is not working:
This is my HTML:
<p class="card-text text-muted h6">{{ post.author }} </p>
{% if post.author == 'John_Woo' %}
<p class="card-text text-muted h6"> NOK </p>
{% else %}
<p class="card-text text-muted h6"> ok </p>
{% endif %}
Not sure what is wrong here...
Even though I have a John_Woo author, I only get ok message
This is my models.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')
This is my views.py:
from django.views import generic
from .models import Post
class PostList(generic.ListView):
queryset = Post.objects.filter(status=1).order_by('-created_on')
template_name = 'index.html'
class PostDetail(generic.DetailView):
model = Post
template_name = 'post_detail.html'
Post.author returns class's representation like(str, unicode, repr) function. You have to override this functions which is depends on your django version. But you have one way to compare this. Like if Post.author.first_name == "John_Woo"
You want post.author.name (where .name is whatever field of an User object that will sometimes contain the string 'John_Woo' )
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.
This is my models.py
class Post(models.Model):
topic = models.CharField(max_length=200)
description = models.TextField()
created_by = models.ForeignKey(User, related_name='posts')
created_on = models.DateTimeField()
class Comment(models.Model):
commented_by = models.ForeignKey(User, related_name='comments')
commented_on = models.ForeignKey(Post, related_name='comments')
commented_text = models.CharField(max_length=500)
commented_time = models.DateTimeField(auto_now_add=True)
class Blogger(models.Model):
username = models.OneToOneField(User, related_name='bloggers')
blogger_bio = models.CharField(max_length=1000)
URL.py for username
url(r'^(?P<username>[a-zA-Z0-9]+)/$', views.author_desc, name='author_desc'),
Views.py
from django.shortcuts import render, get_object_or_404
from .models import Post, User, Comment, Blogger
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
def home(request):
posts_list = Post.objects.all()
return render(request, 'home.html', {'posts': posts})
and my home.html where i want to display:
<!DOCTYPE html>
<html>
<head>
<title>HOME</title>
</head>
<body>
<h2>All Blogs</h2>
{% for post in posts %}
<b>Post Topic: </b>{{ post.topic }}</br>
<b>Published Time: </b>{{ post.created_on }}</br>
<b>Author: </b>{{ post.created_by }}</br></br>
{% endfor %}
</body>
</html>
I want to show each blogger's page from a link from the home. But it is getting problem.
What i'm doing wrong here?
Check whether blogger.username parameter is empty.
Infact the models are not looking that good. The ForeignKey in the Post model should be to the Blogger model.
class Post(models.Model):
created_by = models.ForeignKey(Blogger, related_name='posts')
Then in the template you can do
{% for post in posts %}
<b>Post Topic: </b>{{ post.topic }}</br>
<b>Published Time: </b>{{ post.created_on }}</br>
<b>Author: </b>{{ post.created_by.user }}</br></br>{% endfor %}
Try this
{% for post in posts %}
<b>Post Topic: </b>{{ post.topic }}</br>
<b>Published Time: </b>{{ post.created_on }}</br>
<b>Author: </b>{{ post.created_by }}</br></br>
{% endfor %}