Model层之Migration

1、Migration介绍

Migration 是Django用来将你对models做的改变 (添加一个字段,删除一个model等等) 同步到数据库模式中。

主要用到下面的几个命令:

  • migrate, 主要负责同步;
  • makemigrations, 基于对models做的变化创建新的migration。

2、工作流程
1)当对数据模型做出改变之后,执行python manage.py makemigrations x_app,这是收集某个APP下面的变动。

Migrations for 'books': 0003_auto.py:
- Alter field author on book

执行命令后,模型将被浏览,然后和已经存在的migrations 文件进行比较,然后生成新的migration文件集合。实际上就是讲SQL语句收集起来,但并没有同步到数据库。
migratons文件其实就是普通的py文件。下面是一个初始化文件0001_initial.py(创建数据库):

class Migration(migrations.Migration):

    initial = True

    dependencies = [
        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
    ]

    operations = [
        migrations.CreateModel(
            name='Article',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('title', models.CharField(max_length=150, unique=True, verbose_name='\u6807\u9898')),
                ('alias', models.CharField(max_length=150, verbose_name='\u82f1\u6587\u6807\u9898')),
                ('content', models.TextField(verbose_name='\u6b63\u6587')),
                ('content_html', models.TextField(verbose_name='\u6b63\u6587html\u683c\u5f0f')),
                ('abstract', models.TextField(verbose_name='\u6458\u8981')),
                ('read_times', models.IntegerField(default=0, verbose_name='\u9605\u8bfb\u6b21\u6570')),
                ('tags', models.CharField(help_text='\u7528\u9017\u53f7\u9694\u5f00', max_length=100, verbose_name='\u6807\u7b7e')),
                ('status', models.IntegerField(choices=[(0, '\u6b63\u5e38'), (1, '\u8349\u7a3f'), (2, '\u5220\u9664')], default=0, verbose_name='\u6587\u7ae0\u72b6\u6001')),
                ('create_time', models.DateTimeField(auto_now_add=True)),
                ('pub_time', models.DateTimeField(default=datetime.datetime(2016, 4, 25, 13, 30, 50, 995000))),
                ('update_time', models.DateTimeField(auto_now=True)),
                ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='\u4f5c\u8005')),
            ],
            options={
                'ordering': ['-pub_time', '-create_time'],
                'get_latest_by': 'create_time',
                'verbose_name': '\u6587\u7ae0',
            },
        ),
        migrations.CreateModel(
            name='Category',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(max_length=150, unique=True, verbose_name='\u7c7b\u540d')),
                ('alias', models.CharField(max_length=150, verbose_name='\u82f1\u6587\u540d\u79f0')),
                ('status', models.IntegerField(choices=[(0, '\u6b63\u5e38'), (1, '\u8349\u7a3f'), (2, '\u5220\u9664')], default=0, verbose_name='\u72b6\u6001')),
                ('create_time', models.DateTimeField(auto_now_add=True)),
                ('parent', models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to='blog.Category', verbose_name='\u4e0a\u7ea7\u5206\u7c7b')),
            ],
            options={
                'ordering': ['-create_time'],
                'verbose_name': '\u5206\u7c7b',
            },
        ),
        migrations.AddField(
            model_name='article',
            name='category',
            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='blog.Category', verbose_name='\u5206\u7c7b'),
        ),
    ]

Migration主要有initial,dependency和operation等常用选项。 operation有CreateModel,DeleteModel,ADDField,AlterField等等。
Django源码在django.db.migrations中。

2)执行命令python manage.py migrate

Operations to perform:
Apply all migrations: books
Running migrations:
Rendering model states... DONE
Applying books.0003_auto... OK

该文件扫描变动后的migrations文件,并操作数据库。 注意:上个命令是全局检测的,经常出现No changes detected,所以最好还是加条件选项,指定app。

3、列出所有的迁移情况

Python manager.py makemigrations --list

该命令会列出所有的模型初始化以及变更情况。

4、初始化auth相关模型

当我们第一次执行migrate的时候也会生成user,goup相关模型。它的原理如下: 首先在setting.py定义INSTALLED_APPS:

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'blog',
'rest_framework'
]

'django.contrib.auth'为Django项目中的一个app,然后看Django的源码。在django.contrib.auth中,也有一个migrations文件。果不其然也有一个0001_initial.py文件:

class Migration(migrations.Migration):

dependencies = [
    ('contenttypes', '__first__'),
]

operations = [
    migrations.CreateModel(
        name='Permission',
        fields=[
            ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
            ('name', models.CharField(max_length=50, verbose_name='name')),
            ('content_type', models.ForeignKey(
                to='contenttypes.ContentType',
                on_delete=models.CASCADE,
                to_field='id',
                verbose_name='content type',
            )),
            ('codename', models.CharField(max_length=100, verbose_name='codename')),
        ],
        options={
            'ordering': ('content_type__app_label', 'content_type__model', 'codename'),
            'unique_together': set([('content_type', 'codename')]),
            'verbose_name': 'permission',
            'verbose_name_plural': 'permissions',
        },
        managers=[
            ('objects', django.contrib.auth.models.PermissionManager()),
        ],
    ),
    migrations.CreateModel(
        name='Group',
        fields=[
            ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
            ('name', models.CharField(unique=True, max_length=80, verbose_name='name')),
            ('permissions', models.ManyToManyField(to='auth.Permission', verbose_name='permissions', blank=True)),
        ],
        options={
            'verbose_name': 'group',
            'verbose_name_plural': 'groups',
        },
        managers=[
            ('objects', django.contrib.auth.models.GroupManager()),
        ],
    ),
    migrations.CreateModel(
        name='User',
        fields=[
            ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
            ('password', models.CharField(max_length=128, verbose_name='password')),
            ('last_login', models.DateTimeField(default=timezone.now, verbose_name='last login')),
            ('is_superuser', models.BooleanField(
                default=False,
                help_text='Designates that this user has all permissions without explicitly assigning them.',
                verbose_name='superuser status'
            )),
            ('username', models.CharField(
                help_text='Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.', unique=True,
                max_length=30, verbose_name='username',
                validators=[validators.RegexValidator('^[\\w.@+-]+$', 'Enter a valid username.', 'invalid')]
            )),
            ('first_name', models.CharField(max_length=30, verbose_name='first name', blank=True)),
            ('last_name', models.CharField(max_length=30, verbose_name='last name', blank=True)),
            ('email', models.EmailField(max_length=75, verbose_name='email address', blank=True)),
            ('is_staff', models.BooleanField(
                default=False, help_text='Designates whether the user can log into this admin site.',
                verbose_name='staff status'
            )),
            ('is_active', models.BooleanField(
                default=True, verbose_name='active', help_text=(
                    'Designates whether this user should be treated as active. Unselect this instead of deleting '
                    'accounts.'
                )
            )),
            ('date_joined', models.DateTimeField(default=timezone.now, verbose_name='date joined')),
            ('groups', models.ManyToManyField(
                to='auth.Group', verbose_name='groups', blank=True, related_name='user_set',
                related_query_name='user', help_text=(
                    'The groups this user belongs to. A user will get all permissions granted to each of their '
                    'groups.'
                )
            )),
            ('user_permissions', models.ManyToManyField(
                to='auth.Permission', verbose_name='user permissions', blank=True,
                help_text='Specific permissions for this user.', related_name='user_set',
                related_query_name='user')
             ),
        ],
        options={
            'swappable': 'AUTH_USER_MODEL',
            'verbose_name': 'user',
            'verbose_name_plural': 'users',
        },
        managers=[
            ('objects', django.contrib.auth.models.UserManager()),
        ],
    ),
]

看上面的代码已经很清楚了,定义了goup,user,permission等Model。

--------EOF---------
微信分享/微信扫码阅读