我有一个Scheme模型,只能分配2个奖励,一个用于方案成员,另一个用于他们的朋友。
以下是我为此设计模型的方法,但现在我开始质疑设计,Scheme和奖励的链接是否错误?我是否应该在抽象奖励上反过来呢?
方案:
class Scheme(models.Model):
name = models.CharField(max_length=60)
participant_reward_content_type = models.ForeignKey(ContentType,
editable=False,
related_name='%(app_label)s_%(class)s_as_participant',
null=True, blank=True
)
participant_reward_object_id = models.PositiveIntegerField(null=True, blank=True)
participant_reward = generic.GenericForeignKey('participant_reward_content_type', 'participant_reward_object_id')
friend_reward_content_type = models.ForeignKey(ContentType,
editable=False,
related_name='%(app_label)s_%(class)s_as_friends',
null=True, blank=True
)
friend_reward_object_id = models.PositiveIntegerField(null=True, blank=True)
friend_reward = generic.GenericForeignKey('friend_reward_content_type', 'friend_reward_object_id')
奖励:
class AbstractReward(models.Model):
"""
Abstract reward common information shared for all rewards.
"""
description = models.CharField(max_length="150")
active = models.BooleanField(default=True)
#scheme = models.ForeignKey(Scheme, null=True,)
class Meta:
abstract = True
class SingleVoucherReward(AbstractReward):
"""
Single-use coupons are coupon codes that can only be used once
"""
pass
class Meta:
app_label = 'schemes'
class MultiVoucherReward(AbstractReward):
"""
A multi-use coupon code is a coupon code that can be used unlimited times.
"""
code = models.CharField(max_length=200)
expiry = models.DateTimeField(null=True)
class Meta:
app_label = 'schemes'
class CustomReward(AbstractReward):
"""
A reward class used when it can't be handled or they would like to
handle reward fulfillment themselves.
"""
pass
class Meta:
app_label = 'schemes'
答案 0 :(得分:2)
我建议保持简单 - http://en.wikipedia.org/wiki/KISS_principle
鉴于3种类型奖励的数据定义相似,我完全失去了继承权,只是给它一个类型选择:
class Reward(models.Model):
SINGLE = 'Single'
MULTI = 'Multi'
CUSTOM = 'Custom'
TYPE_CHOICES = (
(SINGLE, 'Single'),
(MULTI, 'Multi'),
(CUSTOM, 'Custom'),
)
description = models.CharField(max_length="150")
active = models.BooleanField(default=True)
type = models.CharField(max_length=10, choices=TYPE_CHOICES, default=SINGLE)
code = models.CharField(max_length=200, blank=True)
expiry = models.DateTimeField(null=True)
Two Scoops of Django - 这是如何在Django中处理事物的一个很好的参考 - 也推荐这种方法。
这也意味着您不需要GenericForeignKey并且可以使用简单的外键,从而大大降低了复杂性:
class Scheme(models.Model):
name = models.CharField(max_length=60)
participant_reward = models.ForeignKey('Reward', null=True, blank=True)
friend_reward = models.ForeignKey('Rewards', null=True, blank=True)
像Django管理员和ModelForms这样的内置功能可以通过这种方法开箱即用。
有些人可能不喜欢TYPE_CHOICES的冗长,但维护起来非常简单明了。
我也意识到你最终可能会在Reward类上使用必须修改不同类型行为的方法,例如:
if self.type = CUSTOM:
pass
但这又是非常简单的维护。如果代码开始真正分歧,你可以使用Proxy Models。
有些人可能认为这不是'Pythonic',但我们不是在这里处理纯Python类,除了Zen of Python状态作为其第三原则:
简单比复杂更好。
答案 1 :(得分:1)
您可以使AbstractReward
不那么抽象(并将其重命名为BaseReward
),然后将ForeignKey
重命名为它,并以某种方式获取实际的奖励类型和对象。您需要提出额外的请求,但我认为它与GenericForeignKey
相同。