#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 и выполнить приведенное выше объединение там.