У меня возникли проблемы с решением, как структурировать мои модели для конкретной структуры данных.
У меня будут следующие модели: Сообщения, Группы, Пользователи.
Я хочу модель Post, которая можетразмещаться на странице групп или на странице пользователя и, возможно, на других страницах, например на странице событий.
Сообщения будут содержать поля для текста, изображений (fk), пользователя, количества просмотров, рейтинга (от - ссылка нагде бы он ни был опубликован с такой же страницы пользователя или группы, хотя я пока не уверен, как установить это соединение)
Я думал об использовании общего внешнего ключа для назначения поля различным моделям, но прочитал статьи предлагая избежать этого.Я попробовал предложенные модели, но я не был уверен, были ли они подходящими для того, что мне требовалось.
На данный момент я выбрал Альтернатива 4 - наследование нескольких таблиц
class Group(models.Model):
name = models.CharField(max_length=64)
created_by = models.ForeignKey(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='_groups')
members = models.ManyToManyField(
settings.AUTH_USER_MODEL)
def __str__(self):
return f'{self.name} -- {self.created_by}'
def save(self, *args, **kwargs):
# https://stackoverflow.com/a/35647389/1294405
created = self._state.adding
super(Group, self).save(*args, **kwargs)
if created:
if not self.members.filter(pk=self.created_by.pk).exists():
self.members.add(self.created_by)
class Post(models.Model):
content = models.TextField(blank=True, default='')
created_by = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name="%(app_label)s_%(class)s_posts",
related_query_name="%(app_label)s_%(class)ss")
# class Meta:
# abstract = True
def __str__(self):
return f'{self.content} -- {self.created_by}'
class PostImage(models.Model):
image = models.ImageField(upload_to=unique_upload)
post = models.ForeignKey(
Post, related_name='images', on_delete=models.CASCADE)
def __str__(self):
return '{}'.format(self.image.name)
class UserPost(models.Model):
post = models.OneToOneField(
Post, null=True, blank=True, related_name='_uPost', on_delete=models.CASCADE)
class GroupPost(models.Model):
post = models.OneToOneField(
Post, null=True, blank=True, related_name='_gPost', on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
Для выполнения некоторых специальных фильтров, например:
Фильтр определенной групповой записи
Post.objects.filter(_gPost__group=group)
Фильтр определенной пользовательской записи
Post.objects.filter(created_by=user) # exclude groups with _gPost__isnull=False
Создать сообщение для пользователя / группы
p = Post.objects.create(...)
up = UserPost.objects.create(post=p)
gp = GroupPost.objects.create(post=p)
Действительно мне интересно, если это разумный подход.Текущий способ фильтра и создания чувствуют себя странно.Так что единственное, что заставляет меня колебаться в этом подходе, это то, как он выглядит.
Итак, Generic ForeignKey - то место, которое можно использовать здесь, или текущий многостоловый подход.Я попытался перейти с наследованием с abstract = True
, но это не сработало, так как мне нужен внешний ключ для базовой модели поста.Даже без абстракции я получил ссылку на внешний ключ, но фильтр стал разочаровывать.
Редактировать:
Пока что при фильтрации нужно учитывать только странные проблемы (но не совсем), я должен быть явноИсключить некоторые поля, чтобы получить то, что я хочу, используя только .filter(created_by=...)
, чтобы получить все другие промежуточные таблицы.Пост фильтра, исключающий все другие планшеты, потребует Post.objects.filter(_uPost__isnull=True, _gPost__isnull=True, _**__isnull=True)
, что может оказаться утомительным.