Django数据库设计

47 阅读2分钟

背景

我们在写前后端分离的项目的过程中一般使用的 DRF (Django Rest Framework) 在使用generics 进行接口的的开发的时候我们是不用进行sql的书写了,我们需要做的是对数据库表结构进行设计,合理的利用数据库表提高数据库的查询性能。

数据库表设计原则

数据库设计要同时满足以下三范式

第一范式

表的字段不可以在拆分
每行都要有主键

第二范式

每行数据必须完全依赖于主键,并不是部分依赖于组件

第三范式

每行的数据依赖是不传递的只依赖主键

合理使用关系

一对一(OneToOneField)两个模型有严格的一对一关系的时候使用
多对一 (ForeignKey) 常见的关联关系
多对多 (ManyToManyField) 需要中间表的情况

模型设计实践

1. 基础模型设计

from django.db import models

class Product(models.Model):
    name = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    description = models.TextField(blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    def __str__(self):
        return self.name

2. 关系设计

多对一关系(ForeignKey)

class Category(models.Model):
    name = models.CharField(max_length=50)

class Product(models.Model):
    category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='products')

多对多关系(ManyToManyField)

class Tag(models.Model):
    name = models.CharField(max_length=50)

class Article(models.Model):
    tags = models.ManyToManyField(Tag, related_name='articles')

自定义中间表


class Membership(models.Model):
    person = models.ForeignKey(Person, on_delete=models.CASCADE)
    group = models.ForeignKey(Group, on_delete=models.CASCADE)
    date_joined = models.DateField()
    invite_reason = models.CharField(max_length=64)

class Group(models.Model):
    members = models.ManyToManyField(Person, through='Membership')

3. 继承策略

抽象基类


class BaseModel(models.Model):
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    class Meta:
        abstract = True

class Product(BaseModel):
    name = models.CharField(max_length=100)

多表继承


class Place(models.Model):
    name = models.CharField(max_length=50)
    address = models.CharField(max_length=80)

class Restaurant(Place):
    serves_hot_dogs = models.BooleanField(default=False)
    serves_pizza = models.BooleanField(default=False)

优化建议

  1. ​索引优化​

    
    class Customer(models.Model):
        email = models.EmailField(db_index=True)
        name = models.CharField(max_length=100, index=True)
    
  2. ​使用 select_related 和 prefetch_related​

    • select_related 用于 ForeignKey 和 OneToOneField
    • prefetch_related 用于 ManyToManyField 和反向 ForeignKey
  3. ​合理使用 choices​

    
    class Order(models.Model):
        STATUS_CHOICES = [
            ('P', 'Pending'),
            ('C', 'Completed'),
            ('F', 'Failed'),
        ]
        status = models.CharField(max_length=1, choices=STATUS_CHOICES, default='P')
    
  4. ​考虑使用 django-model-utils​

    • 提供 TimeStampedModel、StatusModel 等有用基类

常见问题解决方案

  1. ​软删除模式​

    
    class SoftDeleteModel(models.Model):
        is_deleted = models.BooleanField(default=False)
        
        def delete(self, using=None, keep_parents=False):
            self.is_deleted = True
            self.save()
        
        class Meta:
            abstract = True
    
  2. ​多租户设计​

    
    class Tenant(models.Model):
        name = models.CharField(max_length=100)
    
    class TenantAwareModel(models.Model):
        tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE)
        
        class Meta:
            abstract = True
    
  3. ​树形结构​

    from mptt.models import MPTTModel, TreeForeignKey
    
    class Category(MPTTModel):
        name = models.CharField(max_length=50)
        parent = TreeForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='children')
    

通过遵循这些原则和实践,您可以设计出结构合理、易于维护且性能良好的 Django 模型。