Add basis for a comment system

This commit is contained in:
Gabriel Augendre 2020-08-18 18:49:41 +02:00
parent fb2eae301a
commit 698a5ca30f
12 changed files with 233 additions and 11 deletions

View file

@ -5,7 +5,7 @@ from django.contrib.auth.admin import UserAdmin
from django.db import models from django.db import models
from django.shortcuts import redirect from django.shortcuts import redirect
from .models import Article, Page, User from .models import Article, Comment, Page, User
admin.site.register(User, UserAdmin) admin.site.register(User, UserAdmin)
@ -108,3 +108,17 @@ class PageAdmin(ArticleAdmin):
), ),
("Content", {"fields": ("content",)}), ("Content", {"fields": ("content",)}),
] ]
@register(Comment)
class CommentAdmin(admin.ModelAdmin):
list_display = ("username", "email", "content", "article", "created_at", "approved")
list_filter = ("approved",)
search_fields = ("username", "email", "content")
actions = ["approve_comments", "censor_comments"]
def approve_comments(self, request, queryset):
queryset.update(approved=True)
def censor_comments(self, request, queryset):
queryset.update(approved=False)

9
articles/forms.py Normal file
View file

@ -0,0 +1,9 @@
from django import forms
from articles.models import Comment
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ["username", "email", "content"]

View file

@ -0,0 +1,59 @@
# Generated by Django 3.1 on 2020-08-18 16:05
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("articles", "0008_auto_20200817_1748"),
]
operations = [
migrations.CreateModel(
name="Comment",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"username",
models.CharField(
help_text="Will be displayed with your comment.", max_length=255
),
),
(
"email",
models.EmailField(
blank=True,
help_text="Not mandatory, fill only if you want me to be able to contact you. Will never be displayed here nor shared with any third party.",
max_length=254,
null=True,
),
),
(
"content",
models.TextField(
help_text="Your comment, limited to 500 characters.",
max_length=500,
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
(
"article",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="comments",
to="articles.article",
),
),
],
),
]

View file

@ -0,0 +1,21 @@
# Generated by Django 3.1 on 2020-08-18 16:25
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("articles", "0009_comment"),
]
operations = [
migrations.AlterModelOptions(
name="comment", options={"ordering": ["-created_at"]},
),
migrations.AddField(
model_name="comment",
name="active",
field=models.BooleanField(default=False),
),
]

View file

@ -0,0 +1,16 @@
# Generated by Django 3.1 on 2020-08-18 16:29
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("articles", "0010_auto_20200818_1825"),
]
operations = [
migrations.RenameField(
model_name="comment", old_name="active", new_name="approved",
),
]

View file

@ -0,0 +1,21 @@
# Generated by Django 3.1 on 2020-08-18 16:45
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("articles", "0011_auto_20200818_1829"),
]
operations = [
migrations.AlterModelOptions(
name="comment", options={"ordering": ["created_at"]},
),
migrations.AlterField(
model_name="comment",
name="approved",
field=models.BooleanField(default=True),
),
]

View file

@ -92,8 +92,26 @@ class Page(Article):
ordering = ["position", "-published_at"] ordering = ["position", "-published_at"]
# class Comment(models.Model): class Comment(models.Model):
# username = models.CharField(max_length=255) username = models.CharField(
# email = models.EmailField(blank=True, null=True) max_length=255, help_text="Will be displayed with your comment."
# content = models.TextField() )
# article = models.ForeignKey(Article, on_delete=models.CASCADE) email = models.EmailField(
blank=True,
null=True,
help_text=(
"Not mandatory, fill only if you want me to be able to contact you. "
"Will never be displayed here nor shared with any third party."
),
)
content = models.TextField(
max_length=500, help_text="Your comment, limited to 500 characters."
)
article = models.ForeignKey(
Article, on_delete=models.CASCADE, related_name="comments"
)
created_at = models.DateTimeField(auto_now_add=True)
approved = models.BooleanField(default=True)
class Meta:
ordering = ["created_at"]

View file

@ -75,6 +75,10 @@ a:hover, a:focus {
margin-bottom: .2em; margin-bottom: .2em;
} }
.article-detail h1 {
font-size: 2em;
}
.date { .date {
margin-top: .2em; margin-top: .2em;
color: var(--main2); color: var(--main2);

View file

@ -4,11 +4,34 @@
{{ article.title }} {{ article.title }}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div class="article-detail"> <article class="article-detail">
<h1>{{ article.title }}{% if article.status != article.PUBLISHED %} ({{ article.status }}){% endif %}</h1> <h1>{{ article.title }}{% if article.status != article.PUBLISHED %} ({{ article.status }}){% endif %}</h1>
{% include "articles/metadata_snippet.html" %} {% include "articles/metadata_snippet.html" %}
<div> <div>
{{ article.get_formatted_content|safe }} {{ article.get_formatted_content|safe }}
</div> </div>
</div> </article>
<section class="comments">
<h2>Comments</h2>
<form action="{% url 'create-comment' slug=article.slug %}" method="post">
{% csrf_token %}
{{ comment_form.as_p }}
<button type="submit">Submit</button>
</form>
{% for comment in comments %}
<article class="comment">
<p class="metadata">
{{ comment.username }} |
<time datetime="{{ comment.created_at|date:'c' }}">
{{ comment.created_at|date:"DATETIME_FORMAT" }}
</time>
</p>
<p class="content">
{{ comment.content }}
</p>
</article>
{% empty %}
No reaction yet, write your own!
{% endfor %}
</section>
{% endblock %} {% endblock %}

View file

@ -28,6 +28,13 @@
{% endfor %} {% endfor %}
{% endif %} {% endif %}
</nav> </nav>
{% if messages %}
<div class="messages">
{% for message in messages %}
<p>{{ message }}</p>
{% endfor %}
</div>
{% endif %}
<div class="content"> <div class="content">
{% block content %} {% block content %}
{% endblock %} {% endblock %}

View file

@ -1,7 +1,10 @@
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.db.models import F from django.db.models import F
from django.http import HttpResponseRedirect
from django.views import generic from django.views import generic
from articles.forms import CommentForm
from articles.models import Article from articles.models import Article
@ -38,9 +41,19 @@ class ArticleDetailView(generic.DetailView):
template_name = "articles/article_detail.html" template_name = "articles/article_detail.html"
def get_queryset(self): def get_queryset(self):
queryset = super().get_queryset()
if self.request.user.is_authenticated: if self.request.user.is_authenticated:
return super().get_queryset() return queryset
return super().get_queryset().filter(status=Article.PUBLISHED) return queryset.filter(status=Article.PUBLISHED)
def get_context_data(self, **kwargs):
context = super(ArticleDetailView, self).get_context_data(**kwargs)
article = self.object
if hasattr(article, "article"):
article = article.article
context["comments"] = article.comments.filter(approved=True)
context["comment_form"] = CommentForm()
return context
def get_object(self, queryset=None): def get_object(self, queryset=None):
obj = super().get_object(queryset) obj = super().get_object(queryset)
@ -51,3 +64,16 @@ class ArticleDetailView(generic.DetailView):
obj.save(update_fields=["views_count"]) obj.save(update_fields=["views_count"])
return obj return obj
class CreateCommentView(generic.CreateView):
model = Article
form_class = CommentForm
def form_valid(self, form):
self.object = self.get_object()
self.comment = form.save(commit=False)
self.comment.article = self.object
self.comment.save()
messages.success(self.request, "Comment successfully saved.")
return HttpResponseRedirect(self.get_success_url())

View file

@ -22,6 +22,10 @@ urlpatterns = [
path("admin/", admin.site.urls), path("admin/", admin.site.urls),
path("", html.ArticlesListView.as_view(), name="articles-list"), path("", html.ArticlesListView.as_view(), name="articles-list"),
path("drafts/", html.DraftsListView.as_view(), name="drafts-list"), path("drafts/", html.DraftsListView.as_view(), name="drafts-list"),
path("<slug:slug>", html.ArticleDetailView.as_view(), name="article-detail"),
path("feed/", feeds.CompleteFeed(), name="complete-feed"), path("feed/", feeds.CompleteFeed(), name="complete-feed"),
path("<slug:slug>", html.ArticleDetailView.as_view(), name="article-detail"),
path("<slug:slug>/", html.ArticleDetailView.as_view(), name="article-detail"),
path(
"<slug:slug>/comment/", html.CreateCommentView.as_view(), name="create-comment"
),
] ]