@ -0,0 +1,26 @@ |
|||||||
|
# Generated by Django 4.1.1 on 2022-09-23 22:51 |
||||||
|
|
||||||
|
from django.db import migrations, models |
||||||
|
import django.db.models.deletion |
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration): |
||||||
|
|
||||||
|
dependencies = [ |
||||||
|
('article', '0005_rename_tag_article_tags'), |
||||||
|
] |
||||||
|
|
||||||
|
operations = [ |
||||||
|
migrations.CreateModel( |
||||||
|
name='Avatar', |
||||||
|
fields=[ |
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
||||||
|
('content', models.ImageField(upload_to='avatar/%Y%m%d')), |
||||||
|
], |
||||||
|
), |
||||||
|
migrations.AddField( |
||||||
|
model_name='article', |
||||||
|
name='avatar', |
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='articles', to='article.avatar'), |
||||||
|
), |
||||||
|
] |
@ -0,0 +1,19 @@ |
|||||||
|
# Generated by Django 4.1.1 on 2022-09-23 23:57 |
||||||
|
|
||||||
|
from django.db import migrations, models |
||||||
|
import django.db.models.deletion |
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration): |
||||||
|
|
||||||
|
dependencies = [ |
||||||
|
('article', '0006_avatar_article_avatar'), |
||||||
|
] |
||||||
|
|
||||||
|
operations = [ |
||||||
|
migrations.AlterField( |
||||||
|
model_name='article', |
||||||
|
name='avatar', |
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='article', to='article.avatar'), |
||||||
|
), |
||||||
|
] |
@ -0,0 +1,3 @@ |
|||||||
|
from django.contrib import admin |
||||||
|
|
||||||
|
# Register your models here. |
@ -0,0 +1,6 @@ |
|||||||
|
from django.apps import AppConfig |
||||||
|
|
||||||
|
|
||||||
|
class CommentConfig(AppConfig): |
||||||
|
default_auto_field = 'django.db.models.BigAutoField' |
||||||
|
name = 'comment' |
@ -0,0 +1,32 @@ |
|||||||
|
# Generated by Django 4.1.1 on 2022-09-23 23:57 |
||||||
|
|
||||||
|
from django.conf import settings |
||||||
|
from django.db import migrations, models |
||||||
|
import django.db.models.deletion |
||||||
|
import django.utils.timezone |
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration): |
||||||
|
|
||||||
|
initial = True |
||||||
|
|
||||||
|
dependencies = [ |
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL), |
||||||
|
('article', '0007_alter_article_avatar'), |
||||||
|
] |
||||||
|
|
||||||
|
operations = [ |
||||||
|
migrations.CreateModel( |
||||||
|
name='Comment', |
||||||
|
fields=[ |
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
||||||
|
('content', models.TextField()), |
||||||
|
('created', models.DateTimeField(default=django.utils.timezone.now)), |
||||||
|
('article', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to='article.article')), |
||||||
|
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to=settings.AUTH_USER_MODEL)), |
||||||
|
], |
||||||
|
options={ |
||||||
|
'ordering': ['-created'], |
||||||
|
}, |
||||||
|
), |
||||||
|
] |
@ -0,0 +1,30 @@ |
|||||||
|
from django.db import models |
||||||
|
from django.utils import timezone |
||||||
|
from article.models import Article |
||||||
|
from django.contrib.auth.models import User |
||||||
|
|
||||||
|
|
||||||
|
class Comment(models.Model): |
||||||
|
# 评论人 |
||||||
|
author = models.ForeignKey( |
||||||
|
User, |
||||||
|
on_delete=models.CASCADE, |
||||||
|
related_name='comments', |
||||||
|
) |
||||||
|
# 文章 |
||||||
|
article = models.ForeignKey( |
||||||
|
Article, |
||||||
|
on_delete=models.CASCADE, |
||||||
|
related_name='comments', |
||||||
|
) |
||||||
|
# 评论内容 |
||||||
|
content = models.TextField() |
||||||
|
# 评论时间 |
||||||
|
created = models.DateTimeField(default=timezone.now) |
||||||
|
|
||||||
|
class Meta: |
||||||
|
ordering = ['-created'] |
||||||
|
|
||||||
|
def __str__(self): |
||||||
|
# 展示前20个字符 |
||||||
|
return self.content[:20] |
@ -0,0 +1,26 @@ |
|||||||
|
from rest_framework.permissions import BasePermission, SAFE_METHODS |
||||||
|
|
||||||
|
|
||||||
|
class IsOwnerOrReadOnly(BasePermission): |
||||||
|
""" |
||||||
|
只有作者本人可以修改,其他人只能查看 |
||||||
|
""" |
||||||
|
message = "You must be the owner to update" |
||||||
|
|
||||||
|
def safe_methods_or_owner(self, request, func): |
||||||
|
if request.method in SAFE_METHODS: |
||||||
|
return True |
||||||
|
return func() |
||||||
|
|
||||||
|
def has_permission(self, request, view): |
||||||
|
return self.safe_methods_or_owner( |
||||||
|
request, |
||||||
|
lambda: request.user.is_authenticated |
||||||
|
) |
||||||
|
|
||||||
|
def has_object_permission(self, request, view, obj): |
||||||
|
return self.safe_methods_or_owner( |
||||||
|
request, |
||||||
|
lambda: obj.author == request.user # 验证当前评论的作者和当前登录的用户是否为同一个人 |
||||||
|
) |
||||||
|
|
@ -0,0 +1,15 @@ |
|||||||
|
from rest_framework import serializers |
||||||
|
from user_info.serializers import UserDescSerializer |
||||||
|
from comment.models import Comment |
||||||
|
|
||||||
|
|
||||||
|
class CommentSerializer(serializers.ModelSerializer): |
||||||
|
"""评论的序列化器""" |
||||||
|
url = serializers.HyperlinkedIdentityField(view_name='comment-detail') |
||||||
|
author = UserDescSerializer(read_only=True) |
||||||
|
|
||||||
|
class Meta: |
||||||
|
model = Comment |
||||||
|
fields = '__all__' |
||||||
|
extra_kwargs = {'created': {'read_only': True}} |
||||||
|
|
@ -0,0 +1,3 @@ |
|||||||
|
from django.test import TestCase |
||||||
|
|
||||||
|
# Create your tests here. |
@ -0,0 +1,14 @@ |
|||||||
|
from rest_framework import viewsets |
||||||
|
|
||||||
|
from comment.models import Comment |
||||||
|
from comment.serializers import CommentSerializer |
||||||
|
from comment.permissions import IsOwnerOrReadOnly |
||||||
|
|
||||||
|
|
||||||
|
class CommentViewSet(viewsets.ModelViewSet): |
||||||
|
queryset = Comment.objects.all() |
||||||
|
serializer_class = CommentSerializer |
||||||
|
permission_classes = [IsOwnerOrReadOnly] |
||||||
|
|
||||||
|
def perform_create(self, serializer): |
||||||
|
serializer.save(author=self.request.user) |
After Width: | Height: | Size: 1006 B |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 943 B |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.2 KiB |