簡體   English   中英

使用GenericForeignKey的Django模型設計

[英]Django Model Design using GenericForeignKey

我有一個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'

我建議保持它非常簡單 - 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)

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

但這又是非常簡單的維護。 如果代碼開始真正分歧,您可以使用代理模型

有些人可能會爭辯說這不是'Pythonic',但我們並沒有在這里處理純python類,除了PythonZen之外,它還是第三個原則:

簡單比復雜更好。

您可以使您的AbstractReward不那么抽象(並將其重命名為BaseReward ),然后將ForeignKey重命名為它,並在某種方法中獲得實際的獎勵類型和對象。 您需要提出額外的請求,但我認為它與GenericForeignKey相同。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM