我正在创建一个简单的论坛应用程序来学习 Django。我的想法是随着时间的推移创建尽可能多的功能齐全的论坛,但现在这就是我所拥有的:
class Post(models.Model):
post_body = models.TextField(max_length=2000)
publish_date = models.DateTimeField("date posted")
author = models.TextField(max_length=200) # link to User model later
class Meta:
abstract = True
# Post that starts a thread
class ThreadPost(Post):
post_title = models.Charfield(200)
is_solved = models.BooleanField("is_issue_solved", default=False)
class ReplyPost(Post):
is_solution = models.BooleanField("is_this_the_solution", default=False)
thread_post = models.ForeignKey(ThreadPost, on_delete=models.CASCADE)
我不确定这是否有点过头了。
ThreadPost
和ReplyPost
非常相似。我应该创建两个通过继承无关的独立类吗?
我是否应该只上一个
Post
课程,并在回复时将 post_title
设置为可选?我想在这种情况下,单数 Post
类也必须具有递归关系(0 到 N)。
此外,将来我想添加其他功能,例如反应(例如竖起大拇指/竖起大拇指、大笑等)、报告帖子的能力等。我认为这可能是一个单独的模型,链接
Post
和 User
和会有自己的领域。
我想知道什么方法最能保持模型的灵活性以供未来改进。
在考虑是否对 Django 模型进行子类化时,很大程度上取决于您的具体场景,需要更多细节才能给出准确的建议。
该决定应基于您在申请中的观点类型。
例如,如果您需要列出所有线程帖子,那么使用
ThreadPost.objects.all()
检索所有 ThreadPost 对象会很方便。
此外,如果
one-to-many
和 ThreadPost
之间存在 QueryPost
关系,则最好将这两个放在单独的表中。随着项目规模的扩大,这可以帮助最大限度地减少数据库扫描时间。
相反,添加引用两个不同表的反应模型可能会很复杂且难以管理。
我建议考虑您的观点并为您的项目创建一个粗略的 UI/业务框架。这种方法将帮助您在最终创建所需的模型之前有效地标准化表格。
我将给您快速回顾一下建议的代码,然后让我们从缺点问题开始:
ThreadPost
和ReplyPost
)时,添加新字段意味着将其添加到两个模型中,明白吗?例如,添加一个新字段 (
updated_at
)。
为什么我必须在 ThreadPost
和 ReplyPost
中添加 Updated_at 字段?
我不能避免这种冗余吗?
ThreadPost
和ReplyPost
为此,我必须写:
thread = ThreadPost.objects.get(id=1)
replies = ReplyPost.objects.filter(thread_post=thread)
在相同的上下文中,获取两种类型(ThreadPost 和 ReplyPost)的所有帖子怎么样,我必须写:
thread_posts = ThreadPost.objects.all()
reply_posts = ReplyPost.objects.all()
这是我的第一次快速回顾,为了解决这个问题,我认为模型将类似于以下内容:
from django.db import models
from django.contrib.auth.models import User
class Post(models.Model):
post_title = models.CharField(max_length=200, blank=True, null=True)
post_body = models.TextField(max_length=2000)
publish_date = models.DateTimeField("date posted", auto_now_add=True)
author = models.ForeignKey(User, on_delete=models.CASCADE)
parent_post = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='replies')
is_solved = models.BooleanField("is_issue_solved", default=False)
is_solution = models.BooleanField("is_this_the_solution", default=False)
def __str__(self):
return self.post_title or self.post_body[:30]
@property
def is_thread(self):
return self.parent_post is None
@property
def is_reply(self):
return self.parent_post is not None
class Reaction(models.Model):
REACTION_CHOICES = [
('thumbs_up', 'Thumbs Up'),
('thumbs_down', 'Thumbs Down'),
('laugh', 'Laugh'),
# ...
]
post = models.ForeignKey(Post, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
reaction_type = models.CharField(max_length=20, choices=REACTION_CHOICES)
def __str__(self):
return f"{self.user.username} - {self.reaction_type}"
class Report(models.Model):
REPORT_CHOICES = [
('spam', 'Spam'),
('abusive', 'Abusive Content'),
# ...
]
post = models.ForeignKey(Post, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
reason = models.CharField(max_length=20, choices=REPORT_CHOICES)
report_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"{self.user.username} reported {self.post.id} for {self.reason}"