Экземпляр общей модели Django с переопределениями для каждого пользователя

#django #django-models

#django #django-модели

Вопрос:

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

Для этого примера давайте сделаем его страницей магазина, где у пользователей есть свои собственные страницы с белыми метками.

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

Централизованно управляемый элемент:

 class StoreItem(models.Model):
    unit_id = models.CharField(max_length=200, unique=True)
    name = models.CharField(max_length=200)
    description = models.TextField()
    price = models.DecimalField(max_digits=5, decimal_places=2)
 

Элемент, переопределенный пользователем:

 class UserStoreItem(models.model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    item = models.ForeignKey(StoreItem, on_delete=models.CASCADE)

    # I'd like these fields to be inherited from the item ForeignKey if not set
    description = models.TextField(blank=True, null=True)
    price = models.DecimalField(max_digits=5, decimal_places=2, blank=True, null=True)

    class Meta:
        unique_together = (("user", "item"),)
 

Есть ли хороший способ сделать то, что я ищу? Я думал о простом копировании StoreItem для каждого пользователя, однако это потеряло бы возможность централизованного обновления.

Бонусные баллы, если я могу UserStoreItem наследовать StoreItem поля без необходимости определять их дважды.

Ответ №1:

Используя модель данных, как вы определили (я бы использовал то же самое, учитывая перечисленные вами требования). Вы можете считывать данные следующим образом:

 from django.db.models import OuterRef, Subquery
from django.db.models.functions import Coalesce

user_store_items = UserStoreItem.objects.filter(
    user=user,
    item=OuterRef('id')
)
store.items.annotate(
    user_description=Subquery(user_store_items.values('description')[:1]),
    user_price=Subquery(user_store_items.values('description')[:1]),
).annotate(
    calc_description=Coalesce('user_description', 'description'),
    calc_price=Coalesce('user_price', 'price'),
)
 

Этот подход, вероятно, хорош только для нескольких полей. Если их больше 2-5, я бы избегал этого, потому что запрос довольно уродливый. На самом деле, вы можете попробовать использовать extra , чтобы получить строку UserStoreItem и выполнить приведенное выше объединение там.