makemigrations 和 migrate工作原理分别是什么

有一道关于python-django开发工程师的面试题:

  • 内容大致是makemigrations 和 migrate 工作原理分别是什么,
  • 如果不想使用 Django 的 makemigrations 和 migrate 功能,但是不小心执行了这两个命令会发生什么,
  • 如何禁用 migrate 的功能。

下面我们来分析一下这几个问题。

首先:
manage.py是每个django项目中自动生成的一个用于管理项目的脚本文件。需要通过python命令执行。manage.py接受的是Django提供的内置命令。

内置命令包含:

  • check
  • makemigrations
  • migrate
  • runserver
  • startapp
  • startproject
  • 还有其他的我先不写了,这是比较常用的
  • 本篇文章主要根据题目分析makemigrations和migrate

makemigrations:

  • 根据检测到的模型创建新的迁移。迁移的作用,更多的是将数据库的操作,以文件的形式记录下来,方便以后检查、调用、重做等等。

有这样一道很熟悉的命令:

python manger.py makemigrations

相当于在该app下建立 migrations目录,并记录下你所有的关于modes.py的改动,比如0001_initial.py。
但是 这个改动还没有作用到数据库文件
makemigrations 和 migrate工作原理分别是什么

个人白话翻译:也就是说你改了models的时候,你就得删了0001这个日志文件,然后删库重来 python manage.py makemigrations 创建新的迁移

migrate:

  • 使数据库状态与当前模型集和迁移集同步。说白了,就是将对数据库的更改,主要是数据表设计的更改,在数据库中真实执行。例如,新建、修改、删除数据表,新增、修改、删除某数据表内的字段等等。

个人白话翻译:你改了models的时候,数据库也会真实的执行。

在python manger.py makemigrations之后执行命令:

python manager.py migrate
  • 1

就将该改动作用到数据库文件

如何禁用migrate的功能:

Django < 1.9版本时

from settings import *
class DisableMigrations(object):
    def __contains__(self, item):
        return True
    def __getitem__(self, item):
        return 'notmigrations'
MIGRATION_MODULES = DisableMigrations()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

Django >= 1.9版本时
有这么一个配置项目 MIGRATION_MODULES。

from settings import *
MIGRATION_MODULES = {
    'auth': None,
    'contenttypes': None,
    'default': None,
    'sessions': None,
    'core': None,
    'profiles': None,
    'snippets': None,
    'scaffold_templates': None,
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

其他Django版本:

SOUTH_TESTS_MIGRATE = False
  • 1

基于元类设计的makemigrations和migrate

makemigrations和migrate是两条基于元类设计的Django ORM数据库命令

python的元类:

元类就是用来创建类的“东西”。你创建类就是为了创建类的实例对象。
元类就是用来创建这些类(对象)的,元类就是类的类

基于django-ORM的元类

ORM:对象关系映射.
用于实现面向对象编程语言里不同类型系统的数据之间的转换 。从效果上说,它其实是创建了一个可在编程语言里使用的“虚拟对象数据库”。
其本质是通过调用对象实现同等的sql语句

我们来看下面代码:

class Field(object):
    def __init__(self,name,column_tyoe):
        self.name = name
        self.column_type = column_tyoe
    def __str__(self):
        return '&lt;%s:%s&gt;'%(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 ==&gt;%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))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 1

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 的功能。

  • 详情见文中各版本对应设置。
上一篇:用Python制作高逼格数学动画manim


下一篇:安装webgot漏洞实验平台时遇到的java环境配置问题