I am writing a simple blog app and I'm currently in the position where I need to implement comments on a blog post. So, I have two models:
from django.db import models
from django.shortcuts import reverse
# Create your models here.
class Article(models.Model):
title = models.CharField(max_length=120)
author = models.CharField(max_length=50)
content = models.TextField()
date = models.DateField(auto_now=True)
def get_absolute_url(self):
return reverse('articles:article-detail', kwargs={'id': self.id})
class Comment(models.Model):
author = models.CharField(max_length=50)
content = models.TextField()
date = models.DateField(auto_now=True)
post_id = models.IntegerField()
and a ModelForm:
from django import forms
from .models import Article, Comment
class CommentModelForm(forms.ModelForm):
class Meta:
model = Comment
fields = [
'content',
'author',
]
...when I submit the form, I want my Comment's post_id field to be automatically generated and correspond to my Article's id, i.e. the comment should be located on the page where it was submitted.
Here is my views.py:
def article_detail_view(request, id):
obj = get_object_or_404(Article, id=id)
comments = Comment.objects.filter(post_id=id)
comment_form = CommentModelForm(request.POST or None)
if comment_form.is_valid():
comment_form.save()
comment_form = CommentModelForm()
context = {
'object': obj,
'comments': comments,
'comment_form': comment_form
}
return render(request, 'articles/article_detail.html', context)
Any ideas how can I do that?
I suggest to change the Comment model in order to replace post_id with a foreignkey field. It allows to keep a better link between comments and articles.
class Comment(models.Model):
author = models.CharField(max_length=50)
content = models.TextField()
date = models.DateField(auto_now=True)
post_id = models.ForeignKey(Article, on_delete=models.CASCADE) # cascade will delete the comments if the article is deleted.
Then you only have to change the comment_form validation :
if comment_form.is_valid():
comment = comment_form.save(commit=False)
comment.post_id = obj
comment.save()
comment_form = CommentModelForm()
save(commit=False) allows to create the Comment instance without saving it to database and allow us to specify the post_id with the article instance obj defined above. Then comes the final commit comment.save().
If you prefer to not change your model, you can follow the same logic and replace
comment.post_id = obj by comment.post_id = id.
Related
I just started learning Django. I am building a simple Blog App and I am trying to get the user liked time of post of request.user.
I made a Post model and a Like model. And when user like show the like time of user.
But it is not showing the liked time.
models.py
class Post(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=30, default='')
class Likepost(models.Model):
by_user = models.ForeignKey(User, on_delete=models.CASCADE)
post_of = models.ForeignKey(Post, on_delete=models.CASCADE)
date_liked = models.DateTimeField(auto_now_add=True)
views.py
def blog_post_detail(request, post_id):
obj = get_object_or_404(Post, pk=post_id)
accessLikes = obj.likepost_set.all()
for All in accessLikes:
if request.user == All.by_user
All.request.user.date_liked
context = {'obj':obj}
return render(request, 'blog_post_detail.html', context}
What i am trying to do :-
I am trying to access liked time of request.user
It is keep showing :-
Likepost' object has no attribute 'request'
I will really appreciate your help. Thank You
You can obtain the Likepost object of a user by filtering the queryset, and try to retrieve the corresponding like:
def blog_post_detail(request, post_id):
obj = get_object_or_404(Post, pk=post_id)
likepost = obj.likepost_set.filter(by_user=request.user).first()
context = {'obj':obj, 'likepost': likepost}
return render(request, 'blog_post_detail.html', context}
Next you can render this in the template with:
{% if likepost %}
Liked by you at {{ likepost.date_liked }}
{% endif %}
Normally one can prevent multiple Likeposts for the same object and the same user with a UniqueConstraint [Django-doc]:
class Likepost(models.Model):
by_user = models.ForeignKey(User, on_delete=models.CASCADE)
post_of = models.ForeignKey(Post, on_delete=models.CASCADE)
date_liked = models.DateTimeField(auto_now_add=True)
class Meta:
constraints = [
models.UniqueConstraint(
fields=['by_user', 'post_of'],
name='like_once_per_post'
)
]
If you plan to store both like and unlike events, you get the most recent Likemodel with:
def blog_post_detail(request, post_id):
obj = get_object_or_404(Post, pk=post_id)
likepost = obj.likepost_set.filter(by_user=request.user).order_by('-date_liked').first()
# …
'ReverseManyToOneDescriptor' object has no attribute 'filter'
why?)
I'm trying to create a blog in django, got to the stage of adding comments and categories and got stuck
I get an error.
views.py
from django.shortcuts import render,
get_object_or_404
from .models import Post, Comment
from django.views import generic
from django.http import HttpResponse
from .forms import CommentForm
def blog_list(request):
post = Post.objects.all().order_by('-date')
return render(request,'blog/blog_list.html', {'posts':post})
def blog_detail(request, slug):
#return HttpResponse(slug)
detail_post = Post.objects.get(slug=slug)
comments = Post.comments.filter(active=True)
new_comment = None
# Comment posted
if request.method == 'POST':
comment_form = CommentForm(data=request.POST)
if comment_form.is_valid():
# Create Comment object but don't save to database yet
new_comment = comment_form.save(commit=False)
# Assign the current post to the comment
new_comment.post = post
# Save the comment to the database
new_comment.save()
else:
comment_form = CommentForm()
return render(request,'blog/blog_detail.html', {'detail_post':detail_post, 'comments':comments, 'new_comment': new_comment, 'comment_form': comment_form})
I hope someone helps, also with the problem of adding a category
14.comments = Post.comments.filter(active=True) …
▶ Local vars
here is my
models.py
from django.db import models
from django.contrib.auth.models import User
class Post(models.Model):
title = models.CharField(max_length=100)
slug = models.SlugField()
body = models.TextField()
date = models.DateTimeField(auto_now_add=True)
first_src = models.CharField('первоисточник', blank=True, max_length=100)
author = models.ForeignKey(User, on_delete= models.CASCADE )
thumb = models.ImageField(default='default.png', blank=True)
# add AND GO TO MIGRATE AND MAKEMIGRATIONS !!!
class Meta:
ordering = ['-date']
def __str__(self):
return self.title
def snippet(self):
return self.body[:50]+'...'
"""def get_absolute_url(self):
from django.urls import reverse
return reverse("post_detail", kwargs={"slug": str(self.slug)})"""
class Comment(models.Model):
post = models.ForeignKey(Post,
on_delete=models.CASCADE,
related_name='comments')
name = models.CharField(max_length=80)
email = models.EmailField()
body = models.TextField()
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
active = models.BooleanField(default=True)
class Meta:
ordering = ('created',)
def __str__(self):
return 'Comment by {} on {}'.format(self.name, self.post)
What's wrong?
I hope someone helps, also with the problem of adding a category
You're trying to filter on the class (Post), but want to filter on the specific model (detail_post):
comments = detail_post.comments.filter(active=True)
I am following this tutorial: https://tutorial-extensions.djangogirls.org/en/homework_create_more_models/
Which i am adding onto a simple blog I made so i can add comments
Me error:
name 'get_object_or_404' is not defined
From this method in views.py
def add_comment_to_post(request, pk):
post = get_object_or_404(Post, pk=pk)
# post = Post
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.post = post
comment.save()
return redirect('post_detail', pk=post.pk)
else:
form = CommentForm()
return render(request, 'add_comment_to_post.html', {'form': form})
As you see the #hashed out line. This allows me to get to the comment view but then then I get the error that Cannot assign "<class 'blog.models.Post'>": "Comment.post" must be a "Post" instance.
That makes sense but wanted to point that out.
I assume this is a database issue?
my models.py:
from django.db import models
from django.contrib.auth.models import User
STATUS = (
(0,"Draft"),
(1,"Publish")
)
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)
class Meta:
ordering = ['-created_on']
def __str__(self):
return self.title
class Comment(models.Model):
comment = models.CharField(max_length=100)
created_on = models.DateTimeField(auto_now_add=True)
post = models.ForeignKey('blog.Post', on_delete=models.CASCADE, related_name='comments')
def __str__(self):
return self.comment
class Meta:
ordering = ['created_on']
Everything in the tutorial has been followed to a T. I even went through it 3 times, and re copy and pasted everything in, re migrated, etc.
Is there something I am missing the point of?
For the error
name 'get_object_or_404' is not defined
I looked around the blog, and they don't seem to import get_object_or_404. Add to the top of your code:
from django.shortcuts import get_object_or_404
Here is documentation on it.
I have been using django to build a Blog, and when i tried to make a comment section under each post i get the comment icon(where i can type some comments) but when i post the comment i get the error straight away, which is "ContentType matching query does not exist".
I tried to find the problem on stack and youtube but they said that solving this problem requires experience on dumpdata
class Comment(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, default=1, null=True, on_delete=models.SET_NULL)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
content = models.TextField()
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
objects = CommentManager()
def blog_post_detail_view(request, slug):
instance = get_object_or_404(BlogPost, slug=slug)
share_string = quote_plus(instance.content)
initial_data = {
'content_type': instance.get_content_type,
'object_id': instance.id
}
form = CommentForm(request.POST or None, initial=initial_data)
if form.is_valid():
c_type = form.cleaned_data.get('content_type')
content_type = ContentType.objects.get(model=c_type)
obj_id = form.cleaned_data.get('object_id')
content_data = form.cleaned_data.get('content')
new_comment, created = Comment.objects.get_or_create(
user=request.user,
content_type=content_type,
object_id=obj_id,
content=content_data
)
comments = instance.comments
template_name = 'blog/detail.html'
context = {
"object": instance,
'comments': comments,
'share_string': share_string,
'comment_form': form
}
return render(request, template_name, context)
from django import forms
from .models import Comment
class CommentForm(forms.Form):
content_type = forms.CharField(widget=forms.HiddenInput)
object_id = forms.IntegerField(widget=forms.HiddenInput)
content = forms.CharField(widget=forms.Textarea)
So basically i should have gotten my comment posted but instead i get that error:"ContentType matching query does not exist".
Your CommentForm should be a ModelForm, you can set the widgets in the Meta.widgets of the ModelForm
class CommentForm(forms.ModelForm):
class Meta:
model = Meta
fields = ('content_type', 'object_id', 'content')
widgets = {
'content_type': forms.HiddenInput,
'object_id': forms.HiddenInput,
}
This way form.cleaned_data.get('content_type') will contain the actual ContentType object so you don't have to do ContentType.objects.get
After a ModelForm has been submitted, how can I add a foreign key relation so that it validates?
models.py
class Comment(models.Model):
id = models.AutoField(primary_key=True)
activity = models.ForeignKey(Activity)
submitter = models.ForeignKey(User)
creation_date = models.DateTimeField(auto_now_add=True)
content = models.TextField()
forms.py
class CommentForm(forms.ModelForm):
content = forms.CharField(widget=forms.Textarea)
class Meta:
model = Comment
views.py
def index(request, id=None):
activity_instance = Activity.objects.get(pk=1)
submitter_instance = User.objects.get(id=1)
newComment = CommentForm(request.POST)
newComment.activity = activity_instance
newComment.submitter = submitter_instance
if newComment.is_valid(): # <-- false, which is the problem
I think you are mixing up form instance with model instance. your newComment is a form, assigning other objects as a form attribute will not make the form saving the foreign key(not sure where did you find this usage), because all form data is saved in form.data, which is a dict like data structure.
I'm not sure what does your form look like because you didn't exclude the foreign keys so they should be rendered as dropdowns and you could select them. If you don't want the user to select the foreign key but choose to assign the values as you currently do, you should exclude them in the form so form.is_valid() would pass:
class CommentForm(forms.ModelForm):
content = forms.CharField(widget=forms.Textarea)
class Meta:
model = Comment
exclude = ('activity', 'submitter')
views.py
def index(request, id=None):
activity_instance = Activity.objects.get(pk=1)
submitter_instance = User.objects.get(id=1)
comment_form = CommentForm(request.POST)
if comment_form.is_valid():
new_comment = comment_form.save(commit=False)
new_comment.activity = activity_instance
new_comment.submitter = submitter_instance
new_comment.save()
Django doc about save() method.