Add basis for a comment system
This commit is contained in:
parent
fb2eae301a
commit
698a5ca30f
12 changed files with 233 additions and 11 deletions
|
@ -5,7 +5,7 @@ from django.contrib.auth.admin import UserAdmin
|
|||
from django.db import models
|
||||
from django.shortcuts import redirect
|
||||
|
||||
from .models import Article, Page, User
|
||||
from .models import Article, Comment, Page, User
|
||||
|
||||
admin.site.register(User, UserAdmin)
|
||||
|
||||
|
@ -108,3 +108,17 @@ class PageAdmin(ArticleAdmin):
|
|||
),
|
||||
("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
9
articles/forms.py
Normal 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"]
|
59
articles/migrations/0009_comment.py
Normal file
59
articles/migrations/0009_comment.py
Normal 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",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
]
|
21
articles/migrations/0010_auto_20200818_1825.py
Normal file
21
articles/migrations/0010_auto_20200818_1825.py
Normal 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),
|
||||
),
|
||||
]
|
16
articles/migrations/0011_auto_20200818_1829.py
Normal file
16
articles/migrations/0011_auto_20200818_1829.py
Normal 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",
|
||||
),
|
||||
]
|
21
articles/migrations/0012_auto_20200818_1845.py
Normal file
21
articles/migrations/0012_auto_20200818_1845.py
Normal 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),
|
||||
),
|
||||
]
|
|
@ -92,8 +92,26 @@ class Page(Article):
|
|||
ordering = ["position", "-published_at"]
|
||||
|
||||
|
||||
# class Comment(models.Model):
|
||||
# username = models.CharField(max_length=255)
|
||||
# email = models.EmailField(blank=True, null=True)
|
||||
# content = models.TextField()
|
||||
# article = models.ForeignKey(Article, on_delete=models.CASCADE)
|
||||
class Comment(models.Model):
|
||||
username = models.CharField(
|
||||
max_length=255, help_text="Will be displayed with your comment."
|
||||
)
|
||||
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"]
|
||||
|
|
|
@ -75,6 +75,10 @@ a:hover, a:focus {
|
|||
margin-bottom: .2em;
|
||||
}
|
||||
|
||||
.article-detail h1 {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
.date {
|
||||
margin-top: .2em;
|
||||
color: var(--main2);
|
||||
|
|
|
@ -4,11 +4,34 @@
|
|||
{{ article.title }}
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div class="article-detail">
|
||||
<article class="article-detail">
|
||||
<h1>{{ article.title }}{% if article.status != article.PUBLISHED %} ({{ article.status }}){% endif %}</h1>
|
||||
{% include "articles/metadata_snippet.html" %}
|
||||
<div>
|
||||
{{ article.get_formatted_content|safe }}
|
||||
</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 %}
|
||||
|
|
|
@ -28,6 +28,13 @@
|
|||
{% endfor %}
|
||||
{% endif %}
|
||||
</nav>
|
||||
{% if messages %}
|
||||
<div class="messages">
|
||||
{% for message in messages %}
|
||||
<p>{{ message }}</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="content">
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
from django.contrib import messages
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.db.models import F
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.views import generic
|
||||
|
||||
from articles.forms import CommentForm
|
||||
from articles.models import Article
|
||||
|
||||
|
||||
|
@ -38,9 +41,19 @@ class ArticleDetailView(generic.DetailView):
|
|||
template_name = "articles/article_detail.html"
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = super().get_queryset()
|
||||
if self.request.user.is_authenticated:
|
||||
return super().get_queryset()
|
||||
return super().get_queryset().filter(status=Article.PUBLISHED)
|
||||
return queryset
|
||||
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):
|
||||
obj = super().get_object(queryset)
|
||||
|
@ -51,3 +64,16 @@ class ArticleDetailView(generic.DetailView):
|
|||
obj.save(update_fields=["views_count"])
|
||||
|
||||
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())
|
||||
|
|
|
@ -22,6 +22,10 @@ urlpatterns = [
|
|||
path("admin/", admin.site.urls),
|
||||
path("", html.ArticlesListView.as_view(), name="articles-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("<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"
|
||||
),
|
||||
]
|
||||
|
|
Reference in a new issue