我目前必须对我的模型Order
做出以下决定:我使用GenericForeignKey
来引用模型DiscountModel
或AnotherDiscountModel
。只能是其中之一,因此从GenericForeignKey
的想法出发就可以理解。
但是,我在性能很重要的地方实施它。另一种方法是必须在我的模型中的ForeignKey
个字段中:discount_model
和another_discount_model
。其中之一将永远是空的。
我现在想知道在添加“其他折扣模型”之前您将走哪条路。您有什么见识可以与我分享吗?目前,GenericForeignKey
对我来说似乎有点复杂,我将不得不在代码中更改几个部分。
除了Risadinha的评论外,我在这里分享我当前的模型结构:
class AbstractDiscount(TimeStampedModel):
value = models.PositiveIntegerField(
verbose_name=_("Value"),
validators=[
MinValueValidator(0),
],
null=True,
blank=True,
)
percentage = models.DecimalField(
verbose_name=_("Percentage"),
max_digits=5,
decimal_places=4,
validators=[
MinValueValidator(0),
MaxValueValidator(1),
],
null=True,
blank=True,
)
type = models.CharField(
verbose_name=_("Type"),
max_length=10,
choices=TYPE_CHOICES,
)
redeemed_amount = models.PositiveIntegerField(
verbose_name=_("Amount of redeems"),
default=0,
)
class Meta:
abstract = True
class Discount(AbstractDiscount):
available_amount = models.PositiveIntegerField(
verbose_name=_("Available amount"),
)
valid_from = models.DateTimeField(
verbose_name=_("Valid from"),
help_text=_("Choose local time of event location. Leave empty and discount will be valid right away."),
null=True,
blank=True,
)
valid_until = models.DateTimeField(
verbose_name=_("Valid until"),
help_text=_("Choose local time of event location. Leave empty to keep discount valid till the event."),
null=True,
blank=True,
)
comment = models.TextField(
verbose_name=_("Comment"),
help_text=_("Leave some notes for this discount code."),
null=True,
blank=True,
)
status = models.CharField(
verbose_name=_("Status"),
max_length=12,
choices=STATUS_CHOICES,
default=STATUS_ACTIVE,
)
code = models.CharField(
verbose_name=_("Discount code"),
max_length=20,
)
event = models.ForeignKey(
Event,
related_name='discounts',
on_delete=models.CASCADE,
) # CASCADE = delete the discount if the event is deleted
tickets = models.ManyToManyField(
Ticket,
related_name='discounts',
blank=True,
help_text=_("Leave empty to apply this discount to all tickets"),
verbose_name=_("Tickets"),
)
class Meta:
verbose_name = _("Discount")
verbose_name_plural = _("Discounts")
ordering = ['code']
class SocialDiscount(AbstractDiscount):
event = models.OneToOneField(
Event,
related_name='social_ticketing_discount',
on_delete=models.CASCADE,
) # CASCADE = delete the discount if the event is deleted
tickets = models.ManyToManyField(
Ticket,
related_name='social_ticketing_discount',
blank=True,
help_text=_("Leave empty to apply this discount to all tickets"),
verbose_name=_("Tickets"),
)
class Meta:
verbose_name = _("SocialDiscount")
verbose_name_plural = _("SocialDiscount")
答案 0 :(得分:3)
仅出于考虑,对此没有通用的答案。该决定取决于您需要使用此解决方案实施的业务逻辑。
order.discount = ForeignKey(Discount, null=True)
order.social_discount = ForeignKey(SocialDiscount, null=True)
签入后续代码时:
if order.discount:
# do this based on Discount model
elif order.social_discount:
# do that based on SocialDiscount model
这是支持两种截然不同的Discount行为的解决方案。
使用此:
# renamed from AbstractDiscount to ParentDiscount for obvious reasons
order.discount = ForeignKey(ParentDiscount, null=True)
后续代码:
if order.discount:
# do things that apply to either discount
if isinstance(order.discount, 'Discount'):
# do things that only apply to Discount
elif isinstance(order.discount, 'SocialDiscount'):
# do things that only apply to SocialDiscount
使用此:
查询GenericForeignKeys需要一些工作。正如@Andy所说,它不受直接支持,但是您当然可以一起在content_type
和object_id
上进行查询。除非您只能依靠__in
,否则object_id
查找将无法进行。
它将无法以表格的形式立即使用。对于Django Admin,可能有一些解决方案,请参阅GenericForeignKey and Admin in Django。
使用此: