编程符号网的博客   ITGUEST

使用django动态创表与查询

django的分表与动态关联实在是令人扎心,考虑到以后的分表操作,故此debug查看了一波源码,记录一下。

from django.db import models
from django.db import connection


class Book(models.Model):

    @classmethod
    def get_sharding_model(cls, id, flag=True):
        # 简单分表规则
        piece = id % 2 + 1

        class Meta:
            db_table = 'Book_%s' % piece

        attrs = {'Meta': Meta, '__module__': cls.__module__}
        if not flag:
            # 将创建字段的方式改为属性的方式调用
            attrs.update({'name': models.CharField(max_length=256)})
            return type(Meta.db_table, (models.Model,), attrs)
        else:
            return type(Meta.db_table, (cls,), attrs)

    @classmethod
    def sharding_get(cls, id):
        model = cls.get_sharding_model(id=id)
        return model

    @classmethod
    def create_table(cls, id):
        model = cls.get_sharding_model(id=id, flag=False)
        # connection是django初始化的数据库的操作对象,也可以调用相应的api,直接传入sql语句,这里不详细介绍。
        with connection.schema_editor() as schema_editor:
            schema_editor.create_model(model)

    class Meta:
        # 声明为抽象类
        abstract = True

调用方式如下:

Book.create_table(4)
Book= Book.sharding_get(3)
print(Book.objects.all())

今天先到这里了,后续再研究了,orm的动态创建着实痛苦,django的封装太深了,包括使用classmeta…

上述虽然实现了,但是还是感觉不方便,后续阅读了源码,发现model类后初始化一个_meta的属性来接收db_table,而实际上去创建模型的时候用的也是这个表名。

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
from django.db import models
from django.db import connection


class Book(models.Model):
    code = models.CharField(max_length=18, unique=True, verbose_name="编码")
    name = models.CharField(max_length=18, unique=True, verbose_name="名称")

    class Meta:
        db_table = 'book'
        verbose_name = 'Book'
        verbose_name_plural = verbose_name

    @classmethod
    def set_split_table_rule(cls, id):
        # 简单分表规则
        piece = id % 2 + 1
        return piece

    @classmethod
    def get_table_name(cls, id):
        prefix = cls.set_split_table_rule(id)
        return '{}_{}'.format(cls._meta.db_table.split('_')[0], prefix)

    @classmethod
    def set_model_table_name(cls, id=1):
        cls._meta.db_table = cls.get_table_name(id)
        return cls._meta.db_table

    @staticmethod
    def is_exists(table_name):
        return table_name in connection.introspection.table_names()

    @classmethod
    def create_model(cls, id):
        table_name = cls.set_model_table_name(id=id)
        if not cls.is_exists(table_name):
            with connection.schema_editor() as schema_editor:
                schema_editor.create_model(cls)

通过以上可以实现简单的动态分表的操作,至于分库使用数据库路由配置即可。

posted @ 2021-09-05 16:13  java虾米  阅读(685)  评论(0)    收藏  举报