前言
django基本的一些知识已经学到(包括project和app的创建、路由的分发、前后端的交互等),这里就来记录一下django如何使用数据库以及如何连接mysql。
一、数据表的创建
在django中创建数据表是在models.py中来创建的(前面也说过models.py是用来操作数据表的)。那么我们就先在models.py中创建一个数据表(ORM就不做介绍了,在python mysql orm框架----sqlalchemy(一)我也简单提到过):
models.py:
from django.db import models
# Create your models here.
# 数据默认是生成在db.sqlite3中,要想用自己的数据库,就去配置文件settings.py中修改
# 生成的表名叫:app01_userinfo
class UserInfo(models.Model):
# Django会自动创建一列id列,是自增的,并且是主键
# 用户名列,字符串类型,指定长度
username = models.CharField(max_length=32)
password = models.CharField(max_length=64)
在上面这个类中,我们创建了一个userinfo的数据表,这个表在数据库中的名称为:app01_userinfo(因为我是在app01中创建的),其中创建了两列:username、password。当然,Django会自动为我们创建一列id列,这列是自增的,并且是主键。
在创建数据表的代码写完后,接下来该如何操作呢?
接下来就该根据我们的models.py来生成数据表了。
先在终端中执行命令:
python manage.py makemigrations
这时候migrations文件夹就该起作用了,会在这个文件夹中生成一个文件:0001_initial.py:
# Generated by Django 2.2.6 on 2019-10-10 13:27
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='UserInfo',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('username', models.CharField(max_length=32)),
('password', models.CharField(max_length=64)),
],
),
]
前面也提到过,当数据库表结构发生变化的时候,migrations文件夹中就会有相应的记录,具体怎么记录,这里就有了。
接下来执行命令:
python manage.py migrate
这时候数据表就生成了,但并不是生成在我们的mysql中,而是生成在了Django自带的sqlite中。
就是这个db.sqlite3中。
那么我们又该如何来使用我们自己的mysql呢?接下来就来介绍。
二、Django连接mysql
首先要确保我们的机器mysql安装成功。如果没有mysql,则需要先安装mysql。
然后在settings.py中配置mysql。
在settings.py中找到DATABASES:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3', # 默认用sqlite
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
从这里可以看到django默认连接的是sqlite。接下来就将DATABASES配置成mysql:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'cmdb',
'USER':'root',
'PASSWORD':'123456',
'HOST':'localhost',
'POST':'3306',
}
}
注意:这里需要我们做的有以下几点:
- 将’django.db.backends.sqlite3’改成’django.db.backends.mysql’;
- 在我们自己的mysql中创建一个数据表叫cmdb,也就是配置里面的:‘NAME’: ‘cmdb’,(当然,也可以叫别的名称);
- USER和PASSWORD就是mysql中的用户名和密码;
- HOST和POST也要填上。
如果不知道HOST和POST的,可以使用以下方法来获取:
(1)进入数据库
mysql -u root -p
(2)在mysql中输入status:
mysql> status
--------------
C:\mysql\mysql-8.0.17-winx64\bin\mysql.exe Ver 8.0.17 for Win64 on x86_64 (MySQL Community Server - GPL)
Connection id: 18
Current database:
Current user: root@localhost
SSL: Cipher in use is DHE-RSA-AES128-GCM-SHA256
Using delimiter: ;
Server version: 8.0.17 MySQL Community Server - GPL
Protocol version: 10
Connection: localhost via TCP/IP
Server characterset: utf8mb4
Db characterset: utf8mb4
Client characterset: gbk
Conn. characterset: gbk
TCP port: 3306
Uptime: 12 hours 31 min 53 sec
Connection: localhost via TCP/IP;这个就是HOST(填localhost就可以);
TCP port: 3306;这个是PORT。
在settings.py中配置好数据库后重复:
python manage.py makemigrations
python manage.py migrate
这里会有很多问题,接下来我们一一解决。
问题一:
问题描述:
ModuleNotFoundError: No module named 'MySQLdb'
这里的问题是没有“MySQLdb”,我们是不是需要下载MySQLdb呢?
注意:Django使用的与mysql交互的工具是MySQLdb,而我们之前使用的都是pymysql或者mysql-connector。在这里,我们不需要下载MySQLdb,只需要在与项目同名的文件夹下的__init_.py中加入以下代码就可以:
import pymysql
pymysql.install_as_MySQLdb()
加入这个代码以后,再次执行上面的两个命令:
python manage.py makemigrations
python manage.py migrate
问题二:
问题描述:
raise ImproperlyConfigured(‘mysqlclient 1.3.13 or newer is required; you have %s.’ % Database.version)
django.core.exceptions.ImproperlyConfigured: mysqlclient 1.3.13 or newer is required; you have 0.9.3.
File “C:\Python37\lib\site-packages\django\db\backends\mysql\operations.py”, line 146, in last_executed_query
query = query.decode(errors=‘replace’)
AttributeError: ‘str’ object has no attribute ‘decode’
这里其实是两个小问题,先来看第一个问题,第一个问题说的是mysqlclient 版本低,我们第一个想法肯定是升级mysqlclient ,但是先别着急,这里的问题并不是mysqlclient 版本低,而是django2.2内部的一个版本限制在作怪(我用的是django2.2.6),我们只需要修改源码就行。找到mysql下的base.py,将里面的raise ImproperlyConfigured(‘mysqlclient 1.3.13 or newer is required; you have %s.’ % Database.version)注释掉:
# Some of these import MySQLdb, so import them after checking if it's installed.
from .client import DatabaseClient # isort:skip
from .creation import DatabaseCreation # isort:skip
from .features import DatabaseFeatures # isort:skip
from .introspection import DatabaseIntrospection # isort:skip
from .operations import DatabaseOperations # isort:skip
from .schema import DatabaseSchemaEditor # isort:skip
from .validation import DatabaseValidation # isort:skip
# 主要是这里
version = Database.version_info
# if version < (1, 3, 13):
# raise ImproperlyConfigured('mysqlclient 1.3.13 or newer is required; you have %s.' % Database.__version__)
对于第二个问题,将源码中的decode改成encode:
def last_executed_query(self, cursor, sql, params):
# With MySQLdb, cursor objects have an (undocumented) "_executed"
# attribute where the exact query sent to the database is saved.
# See MySQLdb/cursors.py in the source distribution.
query = getattr(cursor, '_executed', None)
if query is not None:
query = query.encode(errors='replace') # 主要是这里,一开始是decode,改成encode
return query
将问题解决后,再次执行命令:
python manage.py makemigrations
结果:
No changes detected
注:这里没有变化的原因是我在上面已经执行过一次了,那个时候是连接的sqlite,接下来我也没有做数据表的修改,所以这里是没有变化的
python manage.py migrate
结果:
Operations to perform:
Apply all migrations: admin, app01, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying app01.0001_initial... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying sessions.0001_initial... OK
看代码的执行结果似乎是成功了,那么就去mysql中看看是不是真的创建上数据表了:
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| cmdb |
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.00 sec)
mysql> use cmdb;
Database changed
mysql> show tables;
+----------------------------+
| Tables_in_cmdb |
+----------------------------+
| app01_userinfo |
| auth_group |
| auth_group_permissions |
| auth_permission |
| auth_user |
| auth_user_groups |
| auth_user_user_permissions |
| django_admin_log |
| django_content_type |
| django_migrations |
| django_session |
+----------------------------+
11 rows in set (0.00 sec)
mysql> desc app01_userinfo;
+----------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| username | varchar(32) | NO | | NULL | |
| password | varchar(64) | NO | | NULL | |
+----------+-------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
mysql>
在上面我们也提到过,生成的数据表的名字是:app01_userinfo,cmdb中也有这个表,我们desc一下发现里面的列也是我们创建的列,当然这里多出一列id来,这里上面也解释过了。
这里有个问题,在cmdb中除了我们自己创建的表以外,还有另外的10个表,这是怎么回事呢?
这是因为django内部的需要,所以在创建我们表的同时,也会创建出额外的表来。
可以简单看一下那些表是干什么的,随便打开一个:
mysql> desc auth_user;
+--------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| password | varchar(128) | NO | | NULL | |
| last_login | datetime(6) | YES | | NULL | |
| is_superuser | tinyint(1) | NO | | NULL | |
| username | varchar(150) | NO | UNI | NULL | |
| first_name | varchar(30) | NO | | NULL | |
| last_name | varchar(150) | NO | | NULL | |
| email | varchar(254) | NO | | NULL | |
| is_staff | tinyint(1) | NO | | NULL | |
| is_active | tinyint(1) | NO | | NULL | |
| date_joined | datetime(6) | NO | | NULL | |
+--------------+--------------+------+-----+---------+----------------+
11 rows in set (0.01 sec)
当然,这些表的具体作用我还在探索当中,如果有小伙伴知道,欢迎评论区留言!!
写在最后
本文是个人的一些学习笔记,如有侵权,请及时联系我进行删除,谢谢大家.