Django GenereicForeignKey v/s пользовательские поля производительности / оптимизации

Я пытаюсь создать типичный сайт социальной сети. В основном это два типа объектов.

  1. Фото
  2. статус

пользователь может понравиться фото и статус. (Обратите внимание, что эти два являются взаимоисключающими) означает, что у нас есть две таблицы (1) только для изображения и другие только для статуса.

теперь, когда пользователю нравится объект (это может быть фотография или статус), как мне хранить эту информацию.

Я хочу разработать эффективную схему SQL для этого. В настоящее время я использую Genericforeignkey(GFK)

class LikedObject(models.Model):
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')

но вчера я подумал, смогу ли я сделать это без эффективного использования ГФК?

class LikedObject(models.Model):

    OBJECT_TYPE = (
        ('status', 'Status'),
        ('image', 'Image/Photo'),
    )

    user = models.ForeignKey(User, related_name="liked_objects")
    obj_id = models.PositiveIntegerField()
    obj_type = models.CharField(max_length=63, choices=OBJECT_TYPE)

единственное отличие, которое я могу понять, заключается в том, что мне нужно сделать два запроса, если я хочу получить все значения like_status конкретного пользователя

status_ids = LikedObject.objects.filter(user=user_obj, obj_type='status').values_list('object_id', flat=True)
status_objs = Status.objects.filter(id__in=status_ids)

Я прав? Итак, что было бы лучшим подходом с точки зрения удобства запросов / вставки или производительности и т. д.

2 ответа

Вы в основном реализуете свой собственный Общий объект, только вы ограничиваете свой ContentType вашим жестко запрограммированным OBJECT_TYPE.

Если вы собираетесь обращаться только к базе данных, как в вашем примере (получить все объекты статуса, понравившиеся пользователю x), или к нескольким конкретным запросам, то, конечно, ваша собственная реализация может быть немного быстрее. Но очевидно, что если позже вам придется добавить больше объектов или заняться чем-то другим, вы можете реализовать все свое полное универсальное решение. И как говорится, зачем изобретать велосипед.

Если вам нужна более высокая производительность, и вам действительно нужно беспокоиться только об этих двух моделях, вы можете просто захотеть иметь две разные таблицы Like (StatusLike и ImageLike) и использовать наследование для совместного использования функциональности.

class LikedObject(models.Model):
   common_field = ...

   class Meta:
      abstract = True

   def some_share_function():
      ...

class StatusLikeObject(LikedObject):
   user = models.ForeignKey(User, related_name="status_liked_objects")
   status = models.ForeignKey(Status, related_name="liked_objects")

class ImageLikeObject(LikedObject):
   user = models.ForeignKey(User, related_name="image_liked_objects")
   image = models.ForeignKey(Image, related_name="liked_objects")

По сути, либо у вас есть много моделей для беспокойства, а затем вы, вероятно, захотите использовать более общую реализацию объектов Django, либо у вас есть только две модели, и зачем даже использовать половинное универсальное решение. Просто используйте две таблицы.

В этом случае я бы проверил, если ваши объекты данных Status а также Photo может иметь много общих полей данных, например Status.user а также Photo.user, Status.title а также Photo.title, Status.pub_date а также Photo.pub_date, Status.text а также Photo.caption, так далее.

Не могли бы вы объединить их в Item объект может быть? Тот Item будет иметь Item.type поле, либо "фото", либо "статус"? Тогда у вас будет только одна таблица и один тип объекта, который может "понравиться" пользователю. Гораздо проще, практически без затрат.

Редактировать:

from django.db import models
from django.utils.timezone import now

class Item(models.Model):
    data_type = models.SmallIntegerField(
        choices=((1, 'Status'), (2, 'Photo')), default=1)
    user = models.ForeignKey(User)
    title = models.CharField(max_length=100)
    pub_date = models.DateTimeField(default=now)
    ...etc...

class Like(models.Model):
    user = models.ForeignKey(User, related_name="liked_objects")
    item = models.ForeignKey(Item)
Другие вопросы по тегам