【发布时间】:2019-02-05 15:42:13
【问题描述】:
我目前必须为我的模型 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")
【问题讨论】:
-
还有另一种选择:如果
DiscountModel和AnotherDiscountModel共享相同的非抽象父模型,您可以在该父模型上使用常规ForeignKey。见docs.djangoproject.com/en/2.1/topics/db/models/… -
您说性能很重要,但您确定选择会产生那么大的影响吗?如果是这样,您可以在基本实现中对其进行测试,如果任何一个选择都可以,请选择
GenericForeignKey或 @Risadinha 的解决方案。 -
@Risadinha 我实际上有一个(当前)抽象类,其中两个模型都是建立的。但是,
AbstractDiscount'不能' 单独存在,因为事件的foreign_key将丢失。您的建议包括将AbstractDiscount设置为非抽象模型,我是否理解正确? -
其他需要考虑的事情:1)您不能在查询过滤器中使用GenericForeignKey; 2) GenericForeignKey 不会出现在 ModelForm 中。这些可能会被取消资格。见docs.djangoproject.com/en/2.1/ref/contrib/contenttypes/…