了解 getattr 函数
教程:https://www.runoob.com/python/python-func-getattr.html
描述
getattr() 函数用于返回一个对象属性值。
语法
getattr 语法:
代码语言:javascript复制getattr(object, name[, default])
参数
- object -- 对象。
- name -- 字符串,对象属性。
- default -- 默认返回值,如果不提供该参数,在没有对应属性时,将触发 AttributeError。
返回值
返回对象属性值。
适用情景
数据表名有一定的规律,根据表名的规律来选择数据表。比如:表名是 user_101, user_102, user_103 以此类推,有规律可循。
组装表名查询
代码语言:javascript复制import myapp.models
def test(requset):
user_db_name = "user_%s" % request.user.name # 组装表名
user_db = getattr(myapp.models, user_db_name)
user_data = user_db.objects.all()
rerurn "..."
一个模型动态创建的多个 db_table
出处:http://www.chenxm.cc/article/764.html
动态创建 table, 并通过 Django ORM 操作.
动态的创建表
动态的创建模型其实就是在运行时生成 Model 类, 这个可以通过函数实现, 通过传参(今天的日期, 如: 20181211),然后生成新的模型类, Meta 中的 db_table 为 log_20181211.
代码语言:javascript复制def get_log_model(prefix):
table_name = 'log_%s' % str(prefix)
LOG_LEVELS = (
(0, 'DEBUG'),
(10, 'INFO'),
(20, 'WARNING'),
)
class LogMetaclass(models.base.ModelBase):
def __new__(cls, name, bases, attrs):
name = '_' prefix # 这是Model的name.
return models.base.ModelBase.__new__(cls, name, bases, attrs)
class Log(models.Model):
__metaclass__ = LogMetaclass
level = models.IntegerField(choices=LOG_LEVELS)
msg = models.TextField()
time = models.DateTimeField(auto_now=True, auto_now_add=True)
@staticmethod
def is_exists():
return table_name in connection.introspection.table_names()
class Meta:
db_table = table_name
return Log
可以看到, 通过函数生成不同的 Log Class. 注意 LogMetaclass 和 __metaclass__ , 元类可以在运行时改变模型的名字,table 的名称我们可以通过 db_table 定义, 类的名称可以通过覆盖元类的方法定义。
代码语言:javascript复制print cls.__name__
Log_20181211
print cls._meta.db_table
log_20181211
使用
使用直接通过函数, 获取当前日期的 Log 模型, 然后通过 is_exists 判读表是否创建, 没有创建则创建对应的表.
代码语言:javascript复制def index(request):
today = date.today().strftime("%Y%m%d")
# RuntimeWarning: Model '__main__.logclasslog_' was already registered.
# Reloading models is not advised as it can lead to inconsistencies
# most notably with related models.
# 如上述警告所述, Django 不建议重复加载 Model 的定义.
# 作为 demo 可以直接通过get_log_model获取,无视警告.
# 所以这里先通过 all_models 获取已经注册的 Model,
# 如果获取不到, 再生成新的模型.
try:
cls = apps.get_model('__main__', 'Log_%s' % today)
except LookupError:
cls = get_log_model(today)
if not cls.is_exists():
with connection.schema_editor() as schema_editor:
schema_editor.create_model(cls)
log = cls(level=10, msg="Hello")
log.save()
return HttpResponse('<h1>%s</h1>' % cls._meta.db_table)
上面获取 cls 部分, 这里的代码先通过 apps 的已经注册的 all_models 获取, 否则一个模型的第二次执行定义代码就会抛出 RuntimeWarning 警告, 在模型的初始化函数都会注册此模型, 最好不要重复注册. 先通过 apps.get_model 获取这个模型, 如果没有获取到则通过 get_log_model 初始化新的模型. 这样做更加稳妥一点.