How do makemigrations and migrate work

Posted by coreDev on Tue, 23 Nov 2021 11:29:43 +0100

There is an interview question about Python Django development engineers:

  • The content is about how makemigrations and migrate work,
  • What happens if you don't want to use Django's make migrations and migrate functions, but accidentally execute these two commands,
  • How to disable migrate.

Let's analyze these problems.

first: manage.py is a script file automatically generated in each Django project to manage the project. It needs to be executed by python command. manage.py accepts the built-in commands provided by Django.

Built in commands include:

  • check
  • makemigrations
  • migrate
  • runserver
  • startapp
  • startproject
  • There are other things I won't write first. This is more commonly used
  • This article mainly analyzes make migrations and migrate according to the title

makemigrations:

  • Create a new migration based on the detected model. The function of migration is more to record the database operations in the form of files, so as to facilitate future inspection, call, redo and so on.

There is a familiar command:

python manger.py makemigrations

It is equivalent to creating the migrations directory under the app and recording all your changes to modes.py, such as 0001_initial.py. However, this change has not yet affected the database file

When you change models, you have to delete 0001, and then delete the library and return to python manage.py Make migrations creates a new migration

migrate:

python manage.py migrate
  • Synchronize the database state with the current model set and migration set. To put it bluntly, changes to the database, mainly changes to the data table design, are actually implemented in the database. For example, create, modify, delete a data table, add, modify, delete fields in a data table, and so on.

When you change the models, the database will actually execute.

In python manger.py Execute the command after makemigrations:

python manager.py migrate

Apply the change to the database file

How to disable migrate:

Django < version 1.9

from settings import *
class DisableMigrations(object):
    def __contains__(self, item):
        return True
    def __getitem__(self, item):
        return 'notmigrations'
MIGRATION_MODULES = DisableMigrations()

Django > = at version 1.9 There is such a configuration item as MIGRATION_MODULES.

from settings import *
MIGRATION_MODULES = {
    'auth': None,
    'contenttypes': None,
    'default': None,
    'sessions': None,
    'core': None,
    'profiles': None,
    'snippets': None,
    'scaffold_templates': None,

Other Django versions:

SOUTH_TESTS_MIGRATE = False

Make migrations and migrate based on metaclass design

makemigrations and migrate are two Django ORM database commands designed based on metaclasses

Metaclass of python:

Metaclasses are the "things" used to create classes. You create a class to create an instance object of the class. Metaclasses are used to create these classes (objects). Metaclasses are classes of classes

Metaclasses based on Django ORM

ORM: object relational mapping It is used to realize the conversion between data of different types of systems in object-oriented programming language. In effect, it actually creates a "virtual object database" that can be used in the programming language. Its essence is to implement equivalent sql statements by calling objects

Let's look at the following code:

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):
    # Define the attribute to column mapping of the class:
    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()

Central idea: use metaclass to create user class, id, name, email, password and other attributes. Pass it to the metaclass. After the metaclass accepts it, it converts them into a dictionary, using __ mapings save, that is, the user uses__ table__ preservation.

This article integrates:

1. How do makemigrations and migrate work

  • Make migrations: create a new migration based on the detected model. The function of migration is more to record the database operations in the form of files, so as to facilitate future inspection, call, redo and so on.
  • migrate: synchronize the database state with the current model set and migration set. To put it bluntly, changes to the database, mainly changes to the data table design, are actually implemented in the database. For example, create, modify, delete a data table, add, modify, delete fields in a data table, and so on.

2. What happens if you don't want to use Django's make migrations and migrate functions, but accidentally execute these two commands,

  • First, create the migrations directory under the app and record all your changes to modes.py, such as 0001_initial.py,
  • Then, if you execute migrate, it will act on the database file and generate the corresponding table

3. How to disable migrate.

  • See the corresponding settings of each version in the text for details.