Django GenereicForeignKey v/s пользовательские поля производительности / оптимизации
Я пытаюсь создать типичный сайт социальной сети. В основном это два типа объектов.
- Фото
- статус
пользователь может понравиться фото и статус. (Обратите внимание, что эти два являются взаимоисключающими) означает, что у нас есть две таблицы (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)