Python/Django支持分布式多租户数据库,如Postgres+Citus。通过向您的查询添加租户上下文来实现轻松扩展,使Citus等数据库能够有效地将查询路由到正确的数据库节点。构建多租户数据库的架构包括:为每个租户创建一个数据库,为每个租户创建一个模式,让所有租户共享同一张表。这个库基于第三种设计,让所有租户共享同一张表,它假设所有与租户相关的模型/表都有一个tenant_id列来表示租户。以下链接详细讨论了何时以及如何为多租户数据库选择正确模式的权衡:https://www.citusdata.com/blog/2016/10/03/designing-your-saas-database-对于-high-scalability/有关多租户的其他有用链接:https://www.citusdata.com/blog/2017/03/09/multi-tenant-sharding-tutorial/https://www.citusdata.com/blog/2017/06/02/scaling-complex-sql-transactions/项目源代码https://github.com/citusdata/django-multitenant安装pipinstall--no-cache-dirdjango_multitenant支持的Django版本/先决条件。PythonDjango3.X2.23.X3.23.X4.0用法要使用此库,您可以使用Mixins或让您的模型继承自我们的自定义模型类。模型变体将其导入到您要使用该库的任何文件中:fromdjango_multitenant.fieldsimport*fromdjango_multitenant.modelsimport*所有模型都应继承TenantModel类。例如:classProduct(TenantModel):定义一个名为tenant_id的静态变量,并使用此变量指定租户列。例如:tenant_id='store_id'TenantModel子类的所有外键都应使用TenantForeignKey而不是models.ForeignKey示例模型来实现上述2个步骤:classStore(TenantModel):tenant_id='id'name=models.CharField(max_length=50)地址=models.CharField(max_length=255)email=models.CharField(max_length=50)classProduct(TenantModel):store=models.ForeignKey(Store)tenant_id='store_id'name=models.CharField(max_length=255)description=models.TextField()classMeta(object):unique_together=["id","store"]classPurchase(TenantModel):store=models.ForeignKey(Store)tenant_id='store_id'product_purchased=TenantForeignKey(Product)更改使用mixins的模型在任何你想使用库的文件中,只需:fromdjango_multitenant.mixinsimport*AllmodelsshoulduseTenantModelMixinanddjangomodels.ModeloryourcustomermodelclassEx:classProduct(TenantModelMixin,models.Model):Define名为tenant_id的静态变量并使用此变量le来指定租户列。例如:tenant_id='store_id'TenantModel子类的所有外键都应使用TenantForeignKey而不是models.ForeignKey示例模型实现上述2个步骤:classProductManager(TenantManagerMixin,models.Manager):passclassProduct(TenantModelMixin,models.Model):store=models.ForeignKey(Store)tenant_id='store_id'name=models.CharField(max_length=255)description=models.TextField()objects=ProductManager()类Meta(object):unique_together=["id","store"]classPurchaseManager(TenantManagerMixin,models.Manager):传递类Purchase(TenantModelMixin,models.Model):store=models.ForeignKey(Store)tenant_id='store_id'product_purchased=TenantForeignKey(Product)objects=PurchaseManager()indb层自动复合外键:使用TenantForeignKey在租户相关模型之间创建外键会自动将tenant_id添加到引用查询(例如product.purchases)和连接查询(例如product__name)。如果要确保在db层创建复合外键(带有tenant_id),则应将settings.py中的数据库ENGINE更改为django_multitenant.backends.postgresql。'default':{'ENGINE':'django_multitenant.backends.postgresql',............}在哪里设置租户?使用中间件编写身份验证逻辑,中间件还为每个会话/请求设置/取消设置租户。这样,开发人员就不必担心在每个视图的基础上设置租户。只需在验证时设置它,库将确保其余部分(将tenant_id过滤器添加到查询中)。上面的例子实现如下:fromdjango_multitenant.utilsimportset_current_tenantclassMultitenantMiddleware:def__init__(self,get_response):self.get_response=get_responsedef__call__(self,request):ifrequest.userandnotrequest.user.is_anonymous_current:set_request.user.employee.company)returnself.get_response(request)在您的设置中,您需要更新MIDDLEWARE设置以包含您创建的设置。MIDDLEWARE=[#...#existingitems#...'appname.middleware.MultitenantMiddleware']根据租户范围在您想要的所有视图中使用set_current_tenant(t)api设置租户。这将自动(无需指定显式过滤器)将所有djangoAPI调用范围限定为单个租户。如果未设置current_tenant,则使用没有租户范围的默认/本机API。支持APIModel.objects.*下的大多数API。Model.save()为租户继承的模型注入tenant_id。s=Store.objects.all()[0]set_current_tenant(s)#以下所有API调用都会添加合适的租户过滤器。#Simpleget_queryset()Product.objects.get_queryset()#SimplejoinPurchase.objects.filter(id=1).filter(store__name='TheAwesomeStore').filter(product__description='Allproductsareawesome')#UpdatePurchase.objects.filter(id=1).update(id=1)#Savep=Product(8,1、'AwesomeShoe','这双鞋真棒')p.save()#SimpleaggregatesProduct.objects.count()Product.objects.filter(store__name='TheAwesomeStore').count()#SubqueriesProduct.objects.filter(name='AwesomeShoe');Purchase.objects.filter(product__in=p);
