I have multiple comments on my homepage, how do i limit the comment to be displayed on a post. Like, i have 10 comments and i want to display only 2 comments.
class Image(models.Model):
imageuploader_profile = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE, null=True, blank=True)
first_upload_image = models.FileField(upload_to ='picmate',null=True, blank=True)
second_upload_image = models.FileField(upload_to ='picmate',null=True, blank=True)
image_caption = models.CharField(max_length=700)
date = models.DateTimeField(auto_now_add=True, null= True)
class Meta:
verbose_name = 'Image'
verbose_name_plural = 'Images'
ordering = ['-date']
def __str__(self):
return self.image_caption
class Comments (models.Model):
comment_post = models.TextField()
author = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE, null=True, blank=True)
commented_image = models.ForeignKey('Image', on_delete=models.CASCADE, related_name='comments')
date = models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name = 'Comment'
verbose_name_plural = 'Comments'
ordering = ['-date']
def __str__(self):
return self.author.__str__()
def home(request):
all_images = Image.objects.filter(imageuploader_profile=request.user.id)
users = User.objects.all()
next = request.GET.get('next')
if next: return redirect(next)
context = {
'all_images': all_images,
'users': users,
}
return render(request,'home.html', context,)
#login_required
def comments(request, id):
post = get_object_or_404(Image,id=id)
# current_user = request.user
print(post)
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.author = request.user
comment.commented_image = post
comment.save()
return redirect('/')
else:
form = CommentForm()
all_comments = Comments.objects.filter(
author=request.user.id,
commented_image=post,
)
{% for comment in post.comments.all %}
<div class="mb-1" style="padding-bottom:-10px;position:relative;top:-10px">
<div class="truncate card-meta dark-grey-text" style="">
<a href="#" class="username dark-grey-text text-lowercase">
{{ comment.author }}</a> {{ comment.comment_post }}
</div>
</div>
{% endfor %}
You can use the django template tag slice
{% for comment in post.comments.all|slice:":2" %}
{{ comment.author }}
{% endfor %}
Related
I'm working on a Django blog and I'm stuck here... I want to post comment and when I do that it just refresh the page and nothing happens.
I have no idea where I'm making a mistake, please see my code below:
this is views.py
def post_detail(request, slug):
post = get_object_or_404(Post, slug=slug)
related_posts = post.tags.similar_objects()[:3]
comments = post.comments.filter(active=True)
new_comment = None
if request.method == 'POST':
if request.user.is_authenticated:
comment_form = CommentForm(data=request.POST)
if comment_form.is_valid():
new_comment = comment_form.save(commit=False)
new_comment.post = post
new_comment.author = request.user
new_comment.save()
else:
messages.warning(request, 'You need to be logged in to add a comment.')
else:
if request.user.is_authenticated:
comment_form = CommentForm(initial={'author': request.user})
else:
comment_form = CommentForm()
context = {'post': post, 'related_posts': related_posts, 'comments': comments, 'new_comment': new_comment, 'comment_form': comment_form}
return render(request, 'post_detail.html', context)
this is comment part post_detail.html
{% if user.is_authenticated %}
<!--comment form-->
<div class="comment-form">
<h3 class="mb-30">Leave a Reply</h3>
<form class="form-contact comment_form" action="{% url 'post_detail' post.slug %}" method="post">
{% csrf_token %}
<div class="row">
<div class="col-12">
<div class="form-group">
{{ comment_form | crispy }}
</div>
</div>
</div>
<div class="form-group">
<button type="submit" class="button button-contactForm">Post Comment</button>
</div>
</form>
</div>
{% else %}
<div class="alert alert-danger" role="alert">
Please log in to post a comment.
</div>
{% endif %}
this is models.py
class Post(models.Model):
created_at = models.DateTimeField(auto_now_add=True, verbose_name="Created at")
updated_at = models.DateTimeField(auto_now=True, verbose_name="Updated at")
published_at = models.DateTimeField(null=True, blank=True, editable=False, verbose_name="Published at")
post_title = models.CharField(max_length=200, verbose_name="Title")
slug = models.SlugField(max_length=200, unique=True)
author = models.ForeignKey('auth.User', verbose_name="Author", on_delete=models.CASCADE)
category = models.ForeignKey(Category, verbose_name="Category", on_delete=models.CASCADE)
tags = TaggableManager()
body = QuillField()
image = StdImageField(upload_to='featured_image/%Y/%m/%d/', variations={'standard':(1170,820),'banner':(1170,530),'single_post':(1170,556),'thumbnail':(500,500)})
image_credit = models.CharField(max_length=200, verbose_name="Image credit:")
status = models.IntegerField(choices=STATUS, default=0)
def get_absolute_url(self):
return reverse('post_detail', args=[self.slug])
def get_readtime(self):
result = readtime.of_text(self.body)
return result.text
class Meta:
verbose_name = "Post"
verbose_name_plural = "Posts"
ordering = ['-created_at']
def publish(self):
self.is_published = True
self.published_at = timezone.now()
self.save()
def __str__(self):
return self.post_title
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
body = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
created_on = models.DateTimeField(auto_now_add=True)
active = models.BooleanField(default=False)
class Meta:
ordering = ['created_on']
def __str__(self):
return 'Comment "{}" by {}'.format(self.body, self.author.username)
this is forms.py
class CommentForm(forms.ModelForm):
author = forms.CharField(widget=forms.HiddenInput)
class Meta:
model = Comment
fields = ('body', 'user')
Please not that I can post comment over admin page (http://127.0.0.1:8000/admin), but on the front-end doesn't work for some reason.
Any ideas?
You need to redirect() after dealing with POST data, the tip is not specific to Django, its a good web practice in general so:
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib import messages
def post_detail(request, slug):
post = get_object_or_404(Post, slug=slug)
related_posts = post.tags.similar_objects()[:3]
comments = post.comments.filter(active=True)
new_comment = None
if request.method == 'POST':
if request.user.is_authenticated:
comment_form = CommentForm(data=request.POST)
if comment_form.is_valid():
new_comment = comment_form.save(commit=False)
new_comment.post = post
new_comment.author = request.user
new_comment.save()
return redirect(post.get_absolute_url()) # redirect here
else:
messages.warning(request, 'You need to be logged in to add a comment.')
else:
if request.user.is_authenticated:
comment_form = CommentForm(initial={'author': request.user})
else:
comment_form = CommentForm()
context = {'post': post, 'related_posts': related_posts, 'comments': comments, 'new_comment': new_comment, 'comment_form': comment_form}
return render(request, 'post_detail.html', context)
I want to make reply of comment function. so I added parent option in Answer model. answer_create() working well.
but, when i submit reply of comment, url is different with url i setting.
i think i should be http://127.0.0.1:8000/debateboard/305/
but return http://127.0.0.1:8000/debateboard/answer/reply/31/
help me plz
models.py
class Question(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='author_question')
subject = models.CharField(max_length=200)
content = models.TextField()
create_date = models.DateTimeField()
modify_date = models.DateTimeField(null=True, blank=True)
voter = models.ManyToManyField(User, related_name='voter_question')
def __str__(self):
return self.subject
class Answer(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='author_answer')
question = models.ForeignKey(Question, on_delete=models.CASCADE)
content = models.TextField()
create_date = models.DateTimeField()
modify_date = models.DateTimeField(null=True, blank=True)
voter = models.ManyToManyField(User, related_name='voter_answer')
######### i added this parent to make reply of comment
parent = models.ForeignKey('self', on_delete=models.CASCADE, blank=True, null=True, related_name='+')
def __str__(self):
return self.content
#property
def children(self):
return Answer.objects.filter(parent=self).order_by('-create_date').all()
#property
def if_parent(self):
if self.parent is None:
return True
return False
urls.py
urlpatterns = [
path('', base_views.index, name = 'index'),
path('<int:question_id>/', base_views.detail, name = 'detail'),
path('answer/create/<int:question_id>/', answer_views.answer_create, name = 'answer_create'),
path('answer/reply/<int:answer_id>/', answer_views.reply_comment_create , name='reply_comment_create'),
view
def detail(request, question_id):
# question = Question.objects.get(id = question_id)
question = get_object_or_404(Question, pk = question_id)
context = {'question' : question}
return render(request, 'debateboard/detail.html', context)
#login_required(login_url='common:login')
def reply_comment_create(request, answer_id):
answer = get_object_or_404(Answer, pk=answer_id)
# question = get_object_or_404(Question, pk = answer.question.id)
if request.method == "POST":
form = AnswerForm(request.POST)
if form.is_valid():
sub_answer = form.save(commit=False)
sub_answer.author = request.user
sub_answer.create_date = timezone.now()
sub_answer.parent = answer.id
sub_answer.save()
# return redirect('{}#answer_{}'.format(resolve_url('debateboard:detail', question_id = answer.question.id), answer.id))
return redirect('debateboard:detail', question_id = answer.question.id)
else:
return HttpResponseNotAllowed('only post is possible')
context = {'question' : answer.question, 'form': form}
return render(request, 'debateboard/detail.html', context)
#login_required(login_url = 'common:login')
def answer_create(request, question_id):
question = get_object_or_404(Question, pk = question_id)
# question.answer_set.create(content=request.POST.get('content'), create_date = timezone.now())
if request.method == 'POST':
form = AnswerForm(request.POST)
if form.is_valid():
answer = form.save(commit=False)
answer.author = request.user
answer.create_date = timezone.now()
answer.question = question
answer.save()
# return redirect('debateboard:detail', question_id = question.id)
return redirect('{}#answer_{}'.format(resolve_url('debateboard:detail', question_id = question.id), answer.id))
else:
return HttpResponseNotAllowed('Only POST is possible.')
context = {'question': question, 'form': form}
return render(request, 'debateboard/detail.html', context)
html
<!-- for reply of comment -->
<form action="{% url 'debateboard:reply_comment_create' answer.id %}" method="POST">
{% csrf_token %}
<div class="form-group">
<textarea name="reply_comment_{{ answer.id }}" id="reply_comment_{{ answer.id }}" cols="20" rows="5"></textarea>
<button type="submit">dd</button>
</div>
</form>
<!-- for comment-->
<form action="{% url 'debateboard:answer_create' question.id %}" method="post">
{% csrf_token %}
<div class="form-group">
<textarea {% if not user.is_authenticated %}disabled placeholder="로그인후 이용가능" {% endif %} name="content" id="content" cols="30" rows="15"></textarea>
</div>
<input {% if not user.is_authenticated %}disabled placeholder="로그인후 이용가능" {% endif %} type="submit" class="btn btn-primary" value="답변등록">
</form>
The address is structured this way because you add an object of class Answer. Anyway, look at how your url is constructed.
path('answer/reply/<int:answer_id>/', answer_views.reply_comment_create , name='reply_comment_create'),
If you want, check the SlugField which can be useful for create custom url.
I want show all Articles from specific category in my template 'category_articles.list.html' at the link: path('category/<name_of_category_SLUG>/'
I have:
URLS
urlpatterns = [
path('show/<int:pk>/<slug:slug>', ArticleDetailView.as_view(), name='article_detail'),
path('all/', AllArticlesListView.as_view(), name='all_articles_list'),
path('category/<slug:slug>/', CategoryArticlesList.as_view(), name='category_articles_list'),
]
MODELS
class Created(models.Model):
created_on = models.DateTimeField(auto_now_add=True, null=True)
class Meta:
abstract = True
class ArticleCategory(Created):
category_name = models.CharField(max_length=128)
slug = models.SlugField(null=False, unique=False)
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.category_name)
return super().save(*args, **kwargs)
def __str__(self):
return self.category_name
class Meta:
verbose_name_plural = 'Article categories'
class Article(Created):
title = models.CharField(max_length=120)
author = models.ForeignKey(User, on_delete=models.CASCADE)
snippet = models.TextField(null=False) # ustawić max_lenght
body = RichTextField(null=False)
category = models.ManyToManyField(ArticleCategory, related_name='articles') # TODO: ustawić on_delete
image = models.ImageField(blank=True, null=True, upload_to='article_image/')
slug = models.SlugField(null=False, unique=False)
def save(self, *args, **kwargs): # opisać tą funckję
if not self.slug:
self.slug = slugify(self.title)
return super().save(*args, **kwargs)
def get_absolute_url(self):
return reverse('news:article_detail', kwargs={'pk': self.pk, 'slug': self.slug})
def article_categories(self):
# zwraca nam wszystkie kategorię artykułu w stringu
return ", \n".join([x.category_name for x in self.category.all()])
def __str__(self):
return f"{self.title}"
class Meta:
verbose_name_plural = 'Articles'
VIEWS
class CategoryArticlesList(DetailView):
template_name = 'news/category_articles_list.html'
model = ArticleCategory
class AllArticlesListView(ListView):
template_name = 'news/articles_list.html'
model = Article
paginate_by = 2
def get_queryset(self):
return self.model.objects.all().order_by('-created_on')
class ArticleDetailView(DetailView):
template_name = 'news/article_detail.html'
model = Article
ARTICLES_LIST.HTML template
ALL NEWS
{% if object_list %}
{% for article in object_list %}
TITLE: {{ article.title }}
CATEGORY_iterator:
{% for category in article.category.iterator %}
{{ category | upper}}
{% endfor %}<br>
ARTICLE_DETAIL.HTML template
ONE SPECIFIC NEWS
<h3>TITLE: {{ article.title }}</h3>
<a href="{% url 'news:article_detail' pk=article.pk slug=article.slug %}">
{% url 'news:article_detail' pk=article.pk slug=article.slug %}</a> <br>
ID:
{{ article.id }} <br>
AUTHOR:
{{ article.author.username }} <br>
CATEGORY_iterator:
{% for category in article.category.iterator %}
{{ category | upper}}
{% endfor %}<br>
finally....
CATEGORY_ARTICLES_LIST.HTMLtemplate
ALL ARTICLES FROM CATEGORY: {{ articlecategory.category_name | upper }}
I don't know how put all articles to ARTICLE_DETAIL.HTML template...
You can iterate all articles from the reverse relation:
articlecategory.articles.all
I am not sure if you can use that in django templates and if it needs to be used with or without the "()".
models.py:
class Object(PolymorphicModel):
author = models.ForeignKey(ProfileUser, on_delete=models.CASCADE)
title = models.CharField(max_length=300)
city = models.ForeignKey(City, on_delete=models.CASCADE)
address = models.CharField(max_length=300)
phone = models.CharField(max_length=20, default='')
email = models.CharField(max_length=100, default='')
site = models.CharField(max_length=100, default='')
facebook = models.CharField(max_length=100, default='')
instagram = models.CharField(max_length=100, default='')
content = models.TextField()
rating = models.DecimalField(default=10.0, max_digits=5, decimal_places=2)
created_date = models.DateTimeField(default=timezone.now)
approved_object = models.BooleanField(default=False)
admin_seen = models.BooleanField(default=False)
def __str__(self):
return f"{self.title}"
class Restaurant(Object):
seats = models.IntegerField()
bulgarian_kitchen = models.BooleanField(default=False)
italian_kitchen = models.BooleanField(default=False)
french_kitchen = models.BooleanField(default=False)
category_en_name = models.CharField(max_length=100, default='restaurants')
category_bg_name = models.CharField(max_length=100, default='Ресторанти')
bg_name = models.CharField(max_length=100, default='Ресторант')
is_garden = models.BooleanField(default=False)
is_playground = models.BooleanField(default=False)
class Images(models.Model):
object = models.ForeignKey(Object, default=None, on_delete=models.CASCADE)
image = models.ImageField(upload_to='attachments',
verbose_name='Image')
forms.py:
class RestaurantForm(forms.ModelForm):
class Meta:
model = Restaurant
fields = [
'title',
'content',
'city',
'address',
'phone',
'email',
'site',
'facebook',
'instagram',
'seats',
'bulgarian_kitchen',
'italian_kitchen',
'french_kitchen',
'is_garden',
'is_playground'
]
class ImageForm(forms.ModelForm):
image = forms.ImageField(label='Снимка')
class Meta:
model = Images
fields = [
'image'
]
template (html):
<form method="post" id="dialog_addObject_part">
{% csrf_token %}
{% for hidden in postForm.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in form %}
<div class="fieldWrapper">
<div class="errorcode{{field.html_name}}">
{{ field.errors }}
</div>
{{ field.label_tag }} {{ field }}
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}
{{ formset.management_form }}
{% for form in formset %}
{{ form }}
{% endfor %}
<div class="utf_addObject_form">
<button type="submit" value="Изпрати">Изпрати</button>
</div>
</form>
views.py:
def add_object(request, category):
if not request.user.is_authenticated:
messages.info(request, 'За да добавите нов Обект, трябва да сте регистриран потребител!')
return redirect('account_login')
form = RestaurantForm(request.POST or None);
ImageFormSet = modelformset_factory(Images,
form=ImageForm, extra=3)
if request.method == 'POST':
formset = ImageFormSet(request.POST, request.FILES)
if form.is_valid() and formset.is_valid():
obj = form.save(commit=False)
obj.author = ProfileUser.objects.get(user=request.user)
obj.save()
print(formset.cleaned_data)
for form in formset.cleaned_data:
if form:
image = form['image']
photo = Images(post=form, image=image)
photo.save()
messages.success(request, 'Успешно добавихте нов Обект, може да видите вашите обекти във вашия профил!')
return redirect('home')
else:
formset = ImageFormSet(queryset=Images.objects.none())
context = {
'form': form,
'formset': formset
}
return render(request, "add_object.html", context)
This row print(formset.cleaned_data) returns me empty objects, so it doesn't upload images.
You missed enctype="multipart/form-data" in html form.
from docs:
Note that request.FILES will only contain data if the request method
was POST and the that posted the request has the attribute
enctype="multipart/form-data". Otherwise, request.FILES will be empty.
Form should be,
<form method="post" id="dialog_addObject_part" enctype="multipart/form-data">
</form>
I'm building a post-comment model in one view, one page, something like facebook. I have two forms in my home.html and view.py: new post and new comment. In each post container, there is a new comment form.
I have a problem because I don't know how to relate comment to post - specifically how to pass post.id to my comment form.
Is it possible to pass my {{ post.id }} to my {{newCommentForm.field }}? That each comment has a default value of post's id?
My home.html:
{% for post in posts %}
<div class="container">
<a class="user" href="#">{{ post.author }}</a>, {{ post.date_posted }}
<img src="{{ post.author.profile.image.url }}" alt="{{ post.author }}"style="width:100%;">
<p>{{ post.content }}</p>
<form METHOD="POST" class="new_post">
{% csrf_token %}
{{ newCommentForm.content }}
{{ newCommentForm.post }}
<button type="submit" name="newCommentSubmit">Add</button>
</form>
</div>
{% endfor %}
models.py
class Post(models.Model):
content = models.TextField(max_length=1000)
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.content
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
author = models.ForeignKey(User, on_delete=models.CASCADE)
content = models.TextField(max_length=500)
date = models.DateTimeField(default=timezone.now)
def add_coment(self):
self.date = timezone.now()
self.save()
def __str__(self):
return self.content
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default='default.jpg', upload_to='profile_pics')
def __str__(self):
return f'{self.user.username}'
views.py
#login_required()
def home(request):
newPostForm = newPost()
newCommentForm = newComment()
if request.method == 'POST':
if 'newPostSubmit' in request.POST:
newPostForm = newPost(request.POST, prefix='newpost')
if newPostForm.is_valid():
instance = newPostForm.save(commit=False)
instance.author = request.user
instance.date_posted = timezone.now()
instance.save()
newCommentForm = newComment(prefix='newcomment')
elif 'newCommentSubmit' in request.POST:
newCommentForm = newComment(request.POST, prefix='newcomment')
if newCommentForm.is_valid():
instance = newCommentForm.save(commit=False)
instance.author = request.user
instance.date_posted = timezone.now()
instance.save()
newPostForm = newPost(prefix='newpost')
else:
newPostForm = newPost(prefix='newpost')
newCommentForm = newComment(prefix='newcomment')
context = {
'newPostForm': newPostForm,
'newCommentForm': newCommentForm,
'posts': Post.objects.all().order_by('-date_posted'),
'comments': Comment.objects.all()
}
return render(request, 'blog/home.html', context)
def about(request):
return render(request, 'blog/about.html')
My model is working now, comments are added, but I need to choose my post (post.id) manually from the default dropdown field witch all posts.
Add your post to comment like this:
if newCommentForm.is_valid():
instance = newCommentForm.save(commit=False)
instance.author = request.user
instance,=.post = request.post
instance.date_posted = timezone.now()
instance.save()
And send post in request!