模型 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()