模型 mixins

在相同情況下,不同的模型在產品生命週期中可以具有相同的欄位和相同的過程。要在沒有程式碼重複的情況下處理這些相似性,可以使用繼承。 mixin 設計模式不是繼承整個類,而是讓我們繼承( 或者說某些包括 )一些方法和屬性。我們來看一個例子:

class PostableMixin(models.Model):
    class Meta:
        abstract=True
    
    sender_name = models.CharField(max_length=128)
    sender_address = models.CharField(max_length=255)
    receiver_name = models.CharField(max_length=128)
    receiver_address = models.CharField(max_length=255)
    post_datetime = models.DateTimeField(auto_now_add=True)
    delivery_datetime = models.DateTimeField(null=True)
    notes = models.TextField(max_length=500)

class Envelope(PostableMixin):
    ENVELOPE_COMMERCIAL = 1
    ENVELOPE_BOOKLET = 2
    ENVELOPE_CATALOG = 3

    ENVELOPE_TYPES = (
        (ENVELOPE_COMMERCIAL, 'Commercial'),
        (ENVELOPE_BOOKLET, 'Booklet'),
        (ENVELOPE_CATALOG, 'Catalog'),
    )

    envelope_type = models.PositiveSmallIntegerField(choices=ENVELOPE_TYPES)

class Package(PostableMixin):
    weight = models.DecimalField(max_digits=6, decimal_places=2)
    width = models.DecimalField(max_digits=5, decimal_places=2)
    height = models.DecimalField(max_digits=5, decimal_places=2)
    depth = models.DecimalField(max_digits=5, decimal_places=2)

要將模型轉換為抽象類,你需要在其內部 Meta 類中提及 abstract=True。Django 不為資料庫中的抽象模型建立任何表。但是對於模型 EnvelopePackage,將在資料庫中建立相應的表。

此外,在一個以上的模型中需要一些模型方法。因此,可以將這些方法新增到 mixin 中以防止程式碼重複。例如,如果我們建立一個方法來將交付日期設定為 PostableMixin,則可以從其兩個子項訪問:

class PostableMixin(models.Model):
    class Meta:
        abstract=True

    ...
    ...

    def set_delivery_datetime(self, dt=None):
        if dt is None:
            from django.utils.timezone import now
            dt = now()

        self.delivery_datetime = dt
        self.save()

這個方法可以用於以下兒童:

>> envelope = Envelope.objects.get(pk=1)
>> envelope.set_delivery_datetime()

>> pack = Package.objects.get(pk=1)
>> pack.set_delivery_datetime()