有一道关于python-django开发工程师的面试题:
- 内容大致是makemigrations 和 migrate 工作原理分别是什么,
- 如果不想使用 Django 的 makemigrations 和 migrate 功能,但是不小心执行了这两个命令会发生什么,
- 如何禁用 migrate 的功能。
下面我们来分析一下这几个问题。
首先: manage.py是每个django项目中自动生成的一个用于管理项目的脚本文件。需要通过python命令执行。manage.py接受的是Django提供的内置命令。
内置命令包含:
- check
- makemigrations
- migrate
- runserver
- startapp
- startproject
- 还有其他的我先不写了,这是比较常用的
- 本篇文章主要根据题目分析makemigrations和migrate
makemigrations:
- 根据检测到的模型创建新的迁移。迁移的作用,更多的是将数据库的操作,以文件的形式记录下来,方便以后检查、调用、重做等等。
有这样一道很熟悉的命令:
代码语言:javascript复制python manger.py makemigrations
相当于在该app下建立 migrations目录,并记录下你所有的关于modes.py的改动,比如0001_initial.py。 但是 这个改动还没有作用到数据库文件
个人白话翻译:也就是说你改了models的时候,你就得删了0001这个日志文件,然后删库重来 python manage.py makemigrations 创建新的迁移
migrate:
代码语言:javascript复制python manage.py migrate
- 使数据库状态与当前模型集和迁移集同步。说白了,就是将对数据库的更改,主要是数据表设计的更改,在数据库中真实执行。例如,新建、修改、删除数据表,新增、修改、删除某数据表内的字段等等。
个人白话翻译:你改了models的时候,数据库也会真实的执行。
在python manger.py makemigrations之后执行命令:
代码语言:javascript复制python manager.py migrate
就将该改动作用到数据库文件
如何禁用migrate的功能:
Django < 1.9版本时
代码语言:javascript复制from settings import *
class DisableMigrations(object):
def __contains__(self, item):
return True
def __getitem__(self, item):
return 'notmigrations'
MIGRATION_MODULES = DisableMigrations()
Django >= 1.9版本时 有这么一个配置项目 MIGRATION_MODULES。
代码语言:javascript复制from settings import *
MIGRATION_MODULES = {
'auth': None,
'contenttypes': None,
'default': None,
'sessions': None,
'core': None,
'profiles': None,
'snippets': None,
'scaffold_templates': None,
其他Django版本:
代码语言:javascript复制SOUTH_TESTS_MIGRATE = False
基于元类设计的makemigrations和migrate
makemigrations和migrate是两条基于元类设计的Django ORM数据库命令
python的元类:
元类就是用来创建类的“东西”。你创建类就是为了创建类的实例对象。 元类就是用来创建这些类(对象)的,元类就是类的类
基于django-ORM的元类
ORM:对象关系映射. 用于实现面向对象编程语言里不同类型系统的数据之间的转换 。从效果上说,它其实是创建了一个可在编程语言里使用的“虚拟对象数据库”。 其本质是通过调用对象实现同等的sql语句
我们来看下面代码:
代码语言:javascript复制class Field(object):
def __init__(self,name,column_tyoe):
self.name = name
self.column_type = column_tyoe
def __str__(self):
return '<%s:%s>'%(self.__class__.__name__,self.name)
class StringField(Field):
def __init__(self,name):
super(StringField,self).__init__(name,"varchar(100)")
class IntegerField(Field):
def __init__(self,name):
super(IntegerField,self).__init__(name,"bigint")
class ModelMetaClass(type):
def __new__(cls, name,bases,attrs):
if name == "Model":
return type.__new__(cls,name,bases,attrs)
print('found model:%s'%name)
mapping = dict()
for k,v in attrs.items():
if isinstance(v,Field):
print("Found mapping:%s ==>%s"%(k,v))
mapping[k] = v
for k in mapping.keys():
attrs.pop(k)
attrs['__mappings__'] = mapping
attrs['__table__'] = name
return type.__new__(cls,name,bases,attrs)
class Model(dict,metaclass = ModelMetaClass):
def __init__(self,**kwargs):
super(Model,self).__init__(**kwargs)
def __getattr__(self, key):
try:
return self[key]
except KeyError:
raise AttributeError("Module objects has no attribute %s"%key)
def __setattr__(self, key, value):
self[key] = value
def save(self):
fields = []
args = []
for k,v in self.__mappings__.items():
fields.append(v.name)
args.append(getattr(self,k,None))
sql = 'insert into %s (%s) values (%s)'%(self.__table__,",".join(fields),",".join(str(i) for i in args))
print("SQL:%s"%sql)
print("ARGS: %s"%str(args))
class User(Model):
# 定义类的属性到列的映射:
id = IntegerField('id')
name = StringField('username')
email = StringField('email')
password = StringField('password')
u = User(id=12345, name='Batman', email='batman@nasa.org', password='iamback')
u.save()
中心思想: 用元类来创建user类,id、name、email、password等属性。传递到元类,元类接受之后把他们转换成字典,用_ _mapings保存,也就是user用__table__保存.
本篇整合:
1、makemigrations 和 migrate 工作原理分别是什么:
- makemigrations:根据检测到的模型创建新的迁移。迁移的作用,更多的是将数据库的操作,以文件的形式记录下来,方便以后检查、调用、重做等等。
- migrate:使数据库状态与当前模型集和迁移集同步。说白了,就是将对数据库的更改,主要是数据表设计的更改,在数据库中真实执行。例如,新建、修改、删除数据表,新增、修改、删除某数据表内的字段等等。
2、如果不想使用 Django 的 makemigrations 和 migrate 功能,但是不小心执行了这两个命令会发生什么,
- 首先在该app下建立 migrations目录,并记录下你所有的关于modes.py的改动,比如0001_initial.py,
- 接着执行migrate的话,这时候会作用到数据库文件,产生对应的表
3、如何禁用 migrate 的功能。
- 详情见文中各版本对应设置。