Я создаю простое приложение-форум, чтобы изучить 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
).
Почему я должен добавить поле update_at как в ThreadPost
, так и в ReplyPost
?
Могу ли я избежать этой избыточности?
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}"
С моей точки зрения, объединение ThreadPost и ReplyPost в единую модель эффективно снижает избыточность. Такой подход сводит к минимуму необходимость обновления нескольких моделей при добавлении новых полей, обеспечивая единый источник достоверной информации и упрощая запросы. Хотя нулевых полей обычно избегают, в нашем случае это компромисс, который упрощает процесс разработки и запроса. Современные базы данных эффективно обрабатывают нулевые значения, поэтому влияние на производительность, вероятно, незначительно. Кроме того, сохраняется целостность данных: значение post_title, равное нулю, указывает на ответ, а значение Parent_post, равное нулю, указывает на публикацию в теме.
Спасибо. Ваш пример имеет большой смысл. Что касается вашего вопроса об избыточности, абстрактный родительский класс был моей попыткой справиться с этим. Т.е. поместите все общие поля в родительский класс. Однако у меня есть один вопрос: разве это не плохая практика проектирования БД — иметь нулевые поля? В вашем примере
post_title
иparent_post
довольно часто могут иметь значение null. Не будет ли это проблемой?