У меня модерационная модель:
class ItemModeration(models.Model):
class Meta:
indexes = [
models.Index(fields=['object_id', 'content_type']),
]
unique_together = ('content_type', 'object_id')
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
item = GenericForeignKey('content_type', 'object_id')
published = models.BooleanField(default=False)
...
Дескриптор для прикрепления объекта модерации на лету:
class ItemModerationDescriptor(object):
def __init__(self, **default_kwargs):
self.default_kwargs = default_kwargs
def __get__(self, instance, owner):
ctype = ContentType.objects.get_for_model(instance.__class__)
try:
moderation = ItemModeration.objects.get(content_type__pk=ctype.id,
object_id=instance.pk)
except ItemModeration.DoesNotExist:
moderation = ItemModeration(item=instance,**self.default_kwargs)
moderation.save()
return moderation
И модель, которую я хочу модерировать:
class Product(models.Model):
user = models.ForeignKey(
User,
null=True,
on_delete=models.SET_NULL)
created = models.DateTimeField(
auto_now_add=True,
blank=True, null=True,
)
modified = models.DateTimeField(
auto_now=True,
blank=True, null=True,
)
name = models.CharField(
max_length=PRODUCT_NAME_MAX_LENGTH,
blank=True, null=True,
)
moderation = ItemModerationDescriptor()
Теперь я легко вижу состояние «опубликовано» продукта:
p=Product(name='my super product')
p.save()
print(p.moderation.published)
-> False
Родовое отношение полезно, потому что я буду в состоянии искать объекты, чтобы модерировать независимо от типа: это могут быть продукты, изображения, комментарии.
to_moderate_qs = ItemModeration.objects.filter(published=False)
Теперь, как я могу получить отфильтрованный список опубликованных продуктов?
Я хотел бы сделать что-то вроде этого
published_products_qs = Product.objects.filter(moderation__published=True, name__icontains='sony')
Но, конечно, он не будет работать, поскольку атрибут moderation
не является полем модели Django.
Как я могу сделать это эффективно? Я подумываю о подходящем JOIN, но не могу понять, как это сделать с помощью django без использования необработанного SQL.