From e5f6a2b113d145c45d13891aa435a834933c5324 Mon Sep 17 00:00:00 2001 From: lele555 <3583165504@qq.com> Date: Sat, 3 Oct 2026 14:07:57 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20project-a/articleapp/model?= =?UTF-8?q?s.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- project-a/articleapp/models.py | 112 +++++++++++++++++++++++++++++++-- 1 file changed, 108 insertions(+), 4 deletions(-) diff --git a/project-a/articleapp/models.py b/project-a/articleapp/models.py index 31a3c79..272c9f3 100644 --- a/project-a/articleapp/models.py +++ b/project-a/articleapp/models.py @@ -1,9 +1,113 @@ from django.db import models +from django.contrib.auth.models import User +from django.db.models.signals import post_save, pre_delete +from django.dispatch import receiver +import json + class Article(models.Model): - title = models.CharField(max_length=100) - content = models.TextField() - create_time = models.DateTimeField(auto_now_add=True) + STATUS_CHOICES = ( + ("draft", "草稿"), + ("published", "已发布"), + ("archived", "归档"), + ) + title = models.CharField(max_length=200, verbose_name="标题") + content = models.TextField(verbose_name="正文") + author = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="作者") + status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="draft", verbose_name="状态") + views = models.PositiveIntegerField(default=0, verbose_name="浏览量") + created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间") + updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间") + is_deleted = models.BooleanField(default=False, verbose_name="是否软删除") # 加分项软删除 def __str__(self): - return self.title \ No newline at end of file + return self.title + + class Meta: + verbose_name = "文章" + verbose_name_plural = "文章" + ordering = ["-created_at"] + + +class Attachment(models.Model): + article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name="attachments", verbose_name="关联文章") + file = models.FileField(upload_to="attachments/", verbose_name="文件") + filename = models.CharField(max_length=200, verbose_name="文件名") + upload_time = models.DateTimeField(auto_now_add=True, verbose_name="上传时间") + downloads = models.PositiveIntegerField(default=0, verbose_name="下载次数") # 加分项下载计数 + + def __str__(self): + return self.filename + + class Meta: + verbose_name = "附件" + verbose_name_plural = "附件" + ordering = ["-upload_time"] + + +class AuditLog(models.Model): + OP_TYPE_CHOICES = ( + ("create", "创建"), + ("update", "更新"), + ("publish", "发布"), + ("archive", "归档"), + ("delete", "删除"), + ) + article = models.ForeignKey(Article, on_delete=models.SET_NULL, null=True, verbose_name="关联文章") + operator = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, verbose_name="操作人") + op_type = models.CharField(max_length=20, choices=OP_TYPE_CHOICES, verbose_name="操作类型") + diff = models.JSONField(default=dict, verbose_name="变更摘要") + time = models.DateTimeField(auto_now_add=True, verbose_name="操作时间") + + def __str__(self): + return f"{self.get_op_type_display()} - {self.article}" + + class Meta: + verbose_name = "审计日志" + verbose_name_plural = "审计日志" + ordering = ["-time"] + + +# ========== Django信号:自动生成审计日志(作业硬性要求!禁止在视图手动创建AuditLog) ========== +@receiver(post_save, sender=Article) +def article_post_save(sender, instance, created,** kwargs): + if created: + # 新建文章 + AuditLog.objects.create( + article=instance, + operator=instance.author, + op_type="create", + diff={"title": instance.title, "status": instance.status} + ) + else: + # 更新文章,记录状态变更 + # kwargs里有update_fields,用来拿到改动字段 + diff_data = {} + if kwargs.get("update_fields") and "status" in kwargs["update_fields"]: + diff_data["status"] = {"new": instance.status} + if instance.status == "published": + op_type = "publish" + elif instance.status == "archived": + op_type = "archive" + else: + op_type = "update" + else: + op_type = "update" + diff_data["title"] = instance.title + AuditLog.objects.create( + article=instance, + operator=instance.author, + op_type=op_type, + diff=diff_data + ) + + +@receiver(pre_delete, sender=Article) +def article_pre_delete(sender, instance,** kwargs): + # 删除文章前触发信号 + AuditLog.objects.create( + article=instance, + operator=instance.author, + op_type="delete", + diff={"title": instance.title} + ) \ No newline at end of file