欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

[Django] Django 连接 MySQL数据库 以及 makemigrations&migrate 过程详解总结

程序员文章站 2022-07-09 19:52:29
...

安装MySQL数据库

Django自带的是SQLite数据库的, 如果要使用MySQL数据库, 则需要重新安装, 安装教程参考
Centos7安装MySQL8过程详解笔记 (附相关错误解决办法)

安装mysqlclient包

  • python访问mysql数据库 需要第三方包, Django推荐使用mysqlclient.
  • 安装命令pip3 install mysqlclient
    (blog) [aaa@qq.com testBlog]# yum install mysqlclient
    Loaded plugins: fastestmirror, langpacks
    Loading mirror speeds from cached hostfile
     * base: mirrors.aliyun.com
     * epel: mirrors.aliyun.com
     * extras: mirrors.aliyun.com
     * updates: mirrors.aliyun.com
    No package mysqlclient available.
    Error: Nothing to do
    (blog) [aaa@qq.com testBlog]# pip3 install mysqlclient
    Collecting mysqlclient
      Using cached mysqlclient-1.4.6.tar.gz (85 kB)
        ERROR: Command errored out with exit status 1:
         command: /root/env/blog/bin/python -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-yl6cmbzb/mysqlclient/setup.py'"'"'; __file__='"'"'/tmp/pip-install-yl6cmbzb/mysqlclient/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' egg_info --egg-base /tmp/pip-install-yl6cmbzb/mysqlclient/pip-egg-info
             cwd: /tmp/pip-install-yl6cmbzb/mysqlclient/
        Complete output (12 lines):
        /bin/sh: mysql_config: command not found
        /bin/sh: mariadb_config: command not found
        /bin/sh: mysql_config: command not found
        Traceback (most recent call last):
          File "<string>", line 1, in <module>
          File "/tmp/pip-install-yl6cmbzb/mysqlclient/setup.py", line 16, in <module>
            metadata, options = get_config()
          File "/tmp/pip-install-yl6cmbzb/mysqlclient/setup_posix.py", line 61, in get_config
            libs = mysql_config("libs")
          File "/tmp/pip-install-yl6cmbzb/mysqlclient/setup_posix.py", line 29, in mysql_config
            raise EnvironmentError("%s not found" % (_mysql_config_path,))
        OSError: mysql_config not found
        ----------------------------------------
    ERROR: Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output.
    
  • 上述报错显示mysql_config变量未找到, 需要安装mysql相关依赖
    yum install mysql-devel
    安装成功后, 继续执行pip3 install mysqlclient
    (blog) [aaa@qq.com bin]# pip3 install mysqlclient
    Collecting mysqlclient
      Using cached mysqlclient-1.4.6.tar.gz (85 kB)
    Building wheels for collected packages: mysqlclient
      Building wheel for mysqlclient (setup.py) ... error
      ERROR: Command errored out with exit status 1:
       command: /root/env/blog/bin/python -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-rqkddtxm/mysqlclient/setup.py'"'"'; __file__='"'"'/tmp/pip-install-rqkddtxm/mysqlclient/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' bdist_wheel -d /tmp/pip-wheel-eexcuz_5
           cwd: /tmp/pip-install-rqkddtxm/mysqlclient/
      Complete output (31 lines):
      running bdist_wheel
      running build
      running build_py
      creating build
      creating build/lib.linux-x86_64-3.6
      creating build/lib.linux-x86_64-3.6/MySQLdb
      copying MySQLdb/__init__.py -> build/lib.linux-x86_64-3.6/MySQLdb
      copying MySQLdb/_exceptions.py -> build/lib.linux-x86_64-3.6/MySQLdb
      copying MySQLdb/compat.py -> build/lib.linux-x86_64-3.6/MySQLdb
      copying MySQLdb/connections.py -> build/lib.linux-x86_64-3.6/MySQLdb
      copying MySQLdb/converters.py -> build/lib.linux-x86_64-3.6/MySQLdb
      copying MySQLdb/cursors.py -> build/lib.linux-x86_64-3.6/MySQLdb
      copying MySQLdb/release.py -> build/lib.linux-x86_64-3.6/MySQLdb
      copying MySQLdb/times.py -> build/lib.linux-x86_64-3.6/MySQLdb
      creating build/lib.linux-x86_64-3.6/MySQLdb/constants
      copying MySQLdb/constants/__init__.py -> build/lib.linux-x86_64-3.6/MySQLdb/constants
      copying MySQLdb/constants/CLIENT.py -> build/lib.linux-x86_64-3.6/MySQLdb/constants
      copying MySQLdb/constants/CR.py -> build/lib.linux-x86_64-3.6/MySQLdb/constants
      copying MySQLdb/constants/ER.py -> build/lib.linux-x86_64-3.6/MySQLdb/constants
      copying MySQLdb/constants/FIELD_TYPE.py -> build/lib.linux-x86_64-3.6/MySQLdb/constants
      copying MySQLdb/constants/FLAG.py -> build/lib.linux-x86_64-3.6/MySQLdb/constants
      running build_ext
      building 'MySQLdb._mysql' extension
      creating build/temp.linux-x86_64-3.6
      creating build/temp.linux-x86_64-3.6/MySQLdb
      gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -fPIC -Dversion_info=(1,4,6,'final',0) -D__version__=1.4.6 -I/usr/include/mysql -I/root/env/blog/include -I/usr/include/python3.6m -c MySQLdb/_mysql.c -o build/temp.linux-x86_64-3.6/MySQLdb/_mysql.o -m64
      MySQLdb/_mysql.c:38:20: fatal error: Python.h: No such file or directory
       #include "Python.h"
                          ^
      compilation terminated.
      error: command 'gcc' failed with exit status 1
      ----------------------------------------
      ERROR: Failed building wheel for mysqlclient
      Running setup.py clean for mysqlclient
    Failed to build mysqlclient
    Installing collected packages: mysqlclient
        Running setup.py install for mysqlclient ... error
        ERROR: Command errored out with exit status 1:
         command: /root/env/blog/bin/python -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-rqkddtxm/mysqlclient/setup.py'"'"'; __file__='"'"'/tmp/pip-install-rqkddtxm/mysqlclient/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record /tmp/pip-record-83ml8lxb/install-record.txt --single-version-externally-managed --compile --install-headers /root/env/blog/include/site/python3.6/mysqlclient
             cwd: /tmp/pip-install-rqkddtxm/mysqlclient/
        Complete output (31 lines):
        running install
        running build
        running build_py
        creating build
        creating build/lib.linux-x86_64-3.6
        creating build/lib.linux-x86_64-3.6/MySQLdb
        copying MySQLdb/__init__.py -> build/lib.linux-x86_64-3.6/MySQLdb
        copying MySQLdb/_exceptions.py -> build/lib.linux-x86_64-3.6/MySQLdb
        copying MySQLdb/compat.py -> build/lib.linux-x86_64-3.6/MySQLdb
        copying MySQLdb/connections.py -> build/lib.linux-x86_64-3.6/MySQLdb
        copying MySQLdb/converters.py -> build/lib.linux-x86_64-3.6/MySQLdb
        copying MySQLdb/cursors.py -> build/lib.linux-x86_64-3.6/MySQLdb
        copying MySQLdb/release.py -> build/lib.linux-x86_64-3.6/MySQLdb
        copying MySQLdb/times.py -> build/lib.linux-x86_64-3.6/MySQLdb
        creating build/lib.linux-x86_64-3.6/MySQLdb/constants
        copying MySQLdb/constants/__init__.py -> build/lib.linux-x86_64-3.6/MySQLdb/constants
        copying MySQLdb/constants/CLIENT.py -> build/lib.linux-x86_64-3.6/MySQLdb/constants
        copying MySQLdb/constants/CR.py -> build/lib.linux-x86_64-3.6/MySQLdb/constants
        copying MySQLdb/constants/ER.py -> build/lib.linux-x86_64-3.6/MySQLdb/constants
        copying MySQLdb/constants/FIELD_TYPE.py -> build/lib.linux-x86_64-3.6/MySQLdb/constants
        copying MySQLdb/constants/FLAG.py -> build/lib.linux-x86_64-3.6/MySQLdb/constants
        running build_ext
        building 'MySQLdb._mysql' extension
        creating build/temp.linux-x86_64-3.6
        creating build/temp.linux-x86_64-3.6/MySQLdb
        gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -fPIC -Dversion_info=(1,4,6,'final',0) -D__version__=1.4.6 -I/usr/include/mysql -I/root/env/blog/include -I/usr/include/python3.6m -c MySQLdb/_mysql.c -o build/temp.linux-x86_64-3.6/MySQLdb/_mysql.o -m64
        MySQLdb/_mysql.c:38:20: fatal error: Python.h: No such file or directory
         #include "Python.h"
                            ^
        compilation terminated.
        error: command 'gcc' failed with exit status 1
        ----------------------------------------
    ERROR: Command errored out with exit status 1: /root/env/blog/bin/python -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-rqkddtxm/mysqlclient/setup.py'"'"'; __file__='"'"'/tmp/pip-install-rqkddtxm/mysqlclient/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record /tmp/pip-record-83ml8lxb/install-record.txt --single-version-externally-managed --compile --install-headers /root/env/blog/include/site/python3.6/mysqlclient Check the logs for full command output.
    
  • 上述报错显示mysql_config变量未找到, 需要安装mysql相关依赖
    yum install python3-devel
    这次安装成功后, 继续执行pip3 install mysqlclient, 成功安装mysqlclient

配置settings.py文件

  • 配置数据库选项
    DATABASES = {
    		    'default': {
    		        'ENGINE': 'django.db.backends.mysql', # 数据库引擎
    		        'NAME': 'djangotest', #数据库名称
    		        'USER': 'root', # 链接数据库的用户名
    		        'PASSWORD': 'root', # 链接数据库的密码
    		        'HOST': '127.0.0.1', # mysql服务器的域名和ip地址
    		        'PORT': '3306', # mysql的一个端口号,默认是3306
    		    }
    		}
    

生成迁移文件

ORM

  • Django是采用ORM技术来操作数据库的

    • ORM(object relation mapping): 对象关系映射, 简单的说这种技术是把数据库中的与面向对象编程中的建立映射, 表中的记录与类的对象建立映射, 记录中的字段与对象中的属性建立映射. 然乎使用面向对象编程的语法来完成对数据库的操作
    据库 面向对象
    对象
    属性
    • 比如执行一条sql语句: select first_name from person where id=10
      ORM可以写成: p=Person.get(10) name = p.first_name
    • ORM封装了数据库的底层操作, 给开发者提供了一层接口, 开发者可以使用熟悉的面向对象编程的语法与数据对象直接
    • ORM的优点
      • 代码变的简单易读
      • 避免了繁琐的sql语句
      • 不用操作表, 使用面向对象的思路进行编程
    • ORM的缺点
      • 开发者无法了解底层数据库的操作, 无法自定义一些复杂的sql
      • ORM 库的语法和相关设置需要重新学习

迁移文件

  • Django中数据模型的代码采用面向对象的思想在app下的models.py中编写, 拥有自己特定的语法格式
  • Django并不是把models.py中的数据模型直接转换成数据库中的表, 而是先把数据模型文件转换成迁移文件, 再由迁移文件生成数据库中的表
    数据模型 ----> 迁移文件 ----> 数据库中的表
  • 迁移文件充当了对象到关系映射的中间使者
  • 迁移文件存放在app下的migrations目录下,

具体操作

  • 将所有app的数据模型转换成迁移文件 (注意: 生成迁移文件的阶段数据库中还没有表)
    python3 manage.py makemigrations

  • 只把特定的app下的数据模型转换成迁移文件
    python3 manage.py makemigrations app_name

  • 查看特定app下特定迁移文件将会生成的sql操作(Django就是根据这些sql操作在数据库中创建表)
    python3 manage.py sqlmigrate app_name 000N
    (所有生成的迁移文件的文件名都有一个000N的编号)
    [Django] Django 连接 MySQL数据库 以及 makemigrations&migrate 过程详解总结

    (blog) [aaa@qq.com migrations]# cat 0001_initial.py 
    # Generated by Django 3.0.5 on 2020-04-09 17:23
    
    from django.db import migrations, models
    
    
    class Migration(migrations.Migration):
    
        initial = True
    
        dependencies = [
        ]
    
        operations = [
            migrations.CreateModel(
                name='Account',
                fields=[
                    ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                    ('user', models.CharField(max_length=40)),
                    ('gender', models.IntegerField()),
                    ('birthday', models.DateField()),
                ],
            ),
        ]```
    
    
  • 显示迁移文件状态: []代表还未迁移, [X]表示已经迁移完毕, 数据库中生成了相应的表
    python3 manage.py showmigrations
    [Django] Django 连接 MySQL数据库 以及 makemigrations&migrate 过程详解总结

  • 每执行一次makemigrations操作, django就会把当前的数据模型和migrations文件夹下最新一次的迁移文件中的数据模型进行对比

    • 如果相同, 则会提示: no changes, 不产生新文件.

    • 如果不同, 则会将这部分不同 涉及的对数据库的更改操作重新生成一个.py文件存放在migrations文件夹下.

    • 除了第一次migrations会有大规模建表的create语句外, 后续的都只是在一些已有表上进行修改的操作, 并不会把数据模型整个重构
      [Django] Django 连接 MySQL数据库 以及 makemigrations&migrate 过程详解总结
      [Django] Django 连接 MySQL数据库 以及 makemigrations&migrate 过程详解总结

      (blog) [aaa@qq.com migrations]# cat 0002_auto_20200409_1914.py 
      # Generated by Django 3.0.5 on 2020-04-09 19:14
      
      from django.db import migrations
      
      
      class Migration(migrations.Migration):
      
          dependencies = [
              ('app1', '0001_initial'),
          ]
      
          operations = [
              migrations.RenameField(
                  model_name='account',
                  old_name='birthday',
                  new_name='school',
              ),
          ]
      

生成数据库的表

  • 将所有app的迁移文件都映射到数据库, 全局映射只会映射还没有映射的文件
    python3 manage.py migrate

  • 指定特定项目的所有迁移文件映射到数据库
    python3 manage.py migrate app_name

  • 指定特定项目下的特定迁移文件映射到数据库
    python3 manage.py migrate app_name 000N

  • 数据库中的表只会和最新一次迁移(migrate)的内容保持一致, 因此如果迁移文件的编号已经到了0007, 并且全部迁移文件都已经迁移过一次. 此时如果再次迁移0005, 那么0006和0007的迁移文件产生的更改会全部被取消, 也就是unapplying
    [Django] Django 连接 MySQL数据库 以及 makemigrations&migrate 过程详解总结
    (迁移第二个文件)
    [Django] Django 连接 MySQL数据库 以及 makemigrations&migrate 过程详解总结
    (迁移三个文件)
    [Django] Django 连接 MySQL数据库 以及 makemigrations&migrate 过程详解总结
    (所有文件都以迁移完毕)
    [Django] Django 连接 MySQL数据库 以及 makemigrations&migrate 过程详解总结
    再次迁移第一个文件
    [Django] Django 连接 MySQL数据库 以及 makemigrations&migrate 过程详解总结
    (第二第三产生的更改全部取)

  • 如果最新一次的迁移再次被执行, Django显示没有需要迁移的文件

    Running migrations:
      No migrations to apply.
      Your models have changes that are not yet reflected in a migration, and so won't be applied.
      Run 'manage.py makemigrations' to make new migrations, and then re-run 'manage.py migrate' to apply them.
    

参考

  1. 第五章:Django连接mysql数据库
  2. 理解Django的makemigrations和migrate
  3. 数据库迁移(migrate)应该知道的一些事