0

I started learning Django about a month ago and just finished Django for Beginners by William Vincent. The book ends with Ch.15: Comments and shows how the admin can add comments to posts.

Q: Can someone, please, show me or point me in the right direction as to how I can let registered users also add comments to posts? Is there perhaps a 3rd party app for that?

What I have so far:

Models:

class Article(models.Model):
title  = models.CharField(max_length=255)
body   = models.TextField()
date   = models.DateTimeField(auto_now_add=True)
image  = models.ImageField(upload_to='images/', null=True, blank=True, height_field=None, width_field=None)
upload = models.FileField(upload_to='files/', null=True, blank=True)
author = models.ForeignKey(
    get_user_model(),
    on_delete=models.CASCADE,
)

def __str__(self):
    return self.title

def get_absolute_url(self):
    return reverse('article_detail', args=[str(self.id)])

class Comment(models.Model):
article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name='comment')
comment = models.CharField(max_length=140)
date    = models.DateTimeField(auto_now_add=True)
author  = models.ForeignKey(
    get_user_model(), on_delete=models.CASCADE,
)

def __str__(self):
    return self.comment

def get_absolute_url(self):
    return reverse('article_list')

forms.py

class PostForm(forms.ModelForm):
class Meta:
    model = Article
    fields = ('title', 'body', 'image', 'upload')

class CommentForm(forms.ModelForm):
class Meta:
    model  = Comment
    fields = ('comment', 'author')

Views:

class ArticleListView(LoginRequiredMixin, ListView):
model         = Article
template_name = 'article_list.html'
comment_form  = CommentForm
login_url     = 'login'

class ArticleDetailView(LoginRequiredMixin, DetailView):
model         = Article
template_name = 'article_detail.html'
login_url     = 'login'

class ArticleUpdateView(LoginRequiredMixin, UpdateView):
model         = Article
fields        = ('title', 'body', 'image', 'upload')
template_name = 'article_edit.html'
login_url     = 'login'

def dispatch(self, request, *args, **kwargs):
    obj = self.get_object()
    if obj.author != self.request.user:
        raise PermissionDenied
    return super().dispatch (request, *args, **kwargs)

class ArticleDeleteView(LoginRequiredMixin, DeleteView):
model         = Article
template_name = 'article_delete.html'
success_url   = reverse_lazy('article_list')
login_url     = 'login'

def dispatch(self, request, *args, **kwargs):
    obj = self.get_object()
    if obj.author != self.request.user:
        raise PermissionDenied
    return super().dispatch (request, *args, **kwargs)

class ArticleCreateView(LoginRequiredMixin, CreateView):
model         = Article
form_class    = PostForm
template_name = 'article_new.html'
login_url     = 'login'

def form_valid(self, form):
    form.instance.author = self.request.user
    return super().form_valid(form)

URLs:

urlpatterns = [
path('<int:pk>/edit/', ArticleUpdateView.as_view(), name='article_edit'),
path('<int:pk>/', ArticleDetailView.as_view(), name='article_detail'),
path('<int:pk>/delete/', ArticleDeleteView.as_view(), name='article_delete'),
path('', ArticleListView.as_view(), name='article_list'),
path('new/', ArticleCreateView.as_view(), name='article_new'),]

Thank you for your attention.

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
  • Edit: I tried to say 'Hello everyone' but that line gets deleted every time? So just saying hello to the community here. I'll be grateful for any pointers. Cheers – codingunicorn Jun 13 '20 at 13:36
  • Can u please calarify more about what do u mean by user form , UserLoginform , or comment box or what – Ahmed Al-Haffar Jun 13 '20 at 14:07
  • Hi Ahmed, sure. The way I understand it for another user to add data that are further stored in the database I need to work with django forms, right? I think I'm missing smth in my view.py, I'm really not sure. I would like to add a comment box right under the post where a user can leave a comment. I'm fairly new to all this so pls bear with me. – codingunicorn Jun 13 '20 at 14:27
  • Welcome to Stack Overflow! We don't really like "greetings" and "thanks" in posts here: it's a more formal site than many other forums. – Adrian Mole Jun 13 '20 at 15:19
  • the DetailView for article-detail would generate a `object` which is article/pk/ so in your template, you can do something like

    {{ object.title }}

    {{ object.body }}

    and after that, you can create a form in the HTML template to display a textbox for comment box only. then, in the view, you can create a new comment where the author value from `request.user` and the comment can be retrieved by request.POST['the name of the textfield in the form']
    – Ahmed Al-Haffar Jun 13 '20 at 15:20
  • @AdrianMole Thank you for the warm welcome. Roger that :) – codingunicorn Jun 16 '20 at 15:54
  • @AhmedAl-Haffar I think I got the form in my html template right. I'm quite sure I'm messing up smth in my views.py at this point. – codingunicorn Jun 16 '20 at 16:02
  • def add_comment(request, pk): article = get_object_or_404(Article, pk=pk) if request.method == "POST": form = CommentForm(request.POST) if form.is_valid(): comment = form.save(commit=False) comment.article = article comment.save() return redirect('post_detail', pk=article.pk) else: form = CommentForm() return render(request, 'add_comment.html', {'form': form}) – codingunicorn Jun 16 '20 at 16:03

1 Answers1

0

Solved. In my views.py I added the following function:

def add_comment(request, pk):
article = get_object_or_404(Article, pk=pk)
if request.method == "POST":
    form = CommentForm(request.POST)
    if form.is_valid():
        comment = form.save(commit=False)
        comment.article = article
        comment.save()
        return redirect('article_detail', pk=article.pk)
else:
    form = CommentForm()
return render(request, 'add_comment.html', {'form': form})

Then the following .html file was added to templates:

add_comment.html

{% extends 'base.html' %}
{% block content %}
<h4>Add a Comment</h4>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<p>{{ form.as_p }}</p>
<button type="submit" class="btn btn-success">Submit</button>
</form>
{% endblock content %}

P.S.: Initially I was getting an ImportError: cannot import name 'add_comment' from 'articles.views'. I thought it was a circular import problem and what worked for me was just getting the def add_comment indentation right.