配置

ORM利用第三方工具连接数据库,可通过setting进行配置

SQLite

Django默认使用SQLite数据库

  1. # settings.py
  2. # ---------------------------------
  3. DATABASES = {
  4. 'default': {
  5. 'ENGINE': 'django.db.backends.sqlite3',
  6. 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
  7. }
  8. }

Mysql

  1. # 使用MySQL 修改settings.py中配置
  2. DATABASES = {
  3. 'default': {
  4. 'ENGINE': 'django.db.backends.mysql',
  5. 'NAME': 'DBName', # 数据库名称
  6. 'USER': 'root', # 数据库用户名
  7. 'PASSWORD': '11111', # 数据库密码
  8. 'HOST': 'localhost', # 数据库地址
  9. 'PORT': '3306' # 数据库端口
  10. 'OPTIONS': {'init_command': 'SET storage_engine=INNODB;'} # 设置刷卡机的引擎INNODB
  11. # 出现 Unknown system variable 'storage_engine'错误时,改为以下
  12. 'OPTIONS': {'init_command': 'SET default_storage_engine=INNODB;'}
  13. }
  14. }
  15. # 默认使用MySQLDB连接mysql,python3中没有MySQLDB,需要修改Django默认连接MySQL方式
  16. 在项目同名目录下的 __init__.py中添加
  17. -------------------------------
  18. import pymysql # 需要先安装pymysql pip3 install pymysql
  19. pymysql.install_as_MySQLdb()
  20. # 也可直接安装 pip3 install mysqlclient Django 2.2 以后必须使用mysqlclient

mysql 8.0+ 错误

  1. # 使用mysql 8.0+版本的包django.db.utils.OperationalError信息
  2. # 因为MySQL8.0版本的密码加密方式发生了改变,cha2加密方法, 需改回原加密方式
  3. ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'newpassword';
  4. FLUSH PRIVILEGES;

ORM表操作

  1. # 使用MySQL 修改settings.py中配置
  2. DATABASES = {
  3. 'default': {
  4. 'ENGINE': 'django.db.backends.mysql',
  5. 'NAME': 'DBName', # 数据库名称
  6. 'USER': 'root', # 数据库用户名
  7. 'PASSWORD': '11111', # 数据库密码
  8. 'HOST': 'localhost', # 数据库地址
  9. 'PORT': '3306' # 数据库端口
  10. }
  11. }
  12. # 默认使用MySQLDB连接mysql,python3中没有MySQLDB,需要修改Django默认连接MySQL方式
  13. 在项目同名目录下的 __init__.py中添加
  14. -------------------------------
  15. import pymysql # 需要先安装pymysql pip3 install pymysql
  16. pymysql.install_as_MySQLdb()

字段总结

  1. # int自增列,必须参数 primary_key=True
  2. models.AutoField()
  3. # bigint自增列,必须参数 primary_key=True
  4. models.BigAutoField()
  5. # 字符字段 max_length 必须设置
  6. models.CharField()
  7. # --------以下数据库中存储为 字符串-------------
  8. ModelForm Django Admin 会对字段验证
  9. models.EmailField() #
  10. models.IPAddressField()
  11. models.URLField()
  12. models.SlugField()
  13. models.UUIDField() # 不重复的一串随机字符
  14. models.FielPathField()
  15. models.FielField()
  16. models.ImageField()
  17. models.CommaSeparatedIntegerField()
  18. #-------------------------------------------
  19. # 时间类 插入数据时可以是datetime类型 也可以是字符串 ‘2017-11-11’
  20. models.DateTimeField()
  21. models.DateField()
  22. # 整型字段
  23. models.IntegerField()
  24. # 浮点字段
  25. models.FloatField()
  26. # decimal字段
  27. models.DecimalField(max_digits=30, decimal_places=10)
  28. # 枚举(Django) 选项固定不变时
  29. choices = ((1, '项1'), (2, '项2'))
  30. models.IntegerField(choices=choices) # 也可以是CharField
  31. # 外键
  32. models.ForeignKey('类名')
  33. 参数(对数据库列):
  34. max_length 长度
  35. default 默认值
  36. null=True 可以为空
  37. primary_key=True 主键
  38. db_index=True 索引
  39. unique=True 唯一索引
  40. unique_for_date 为时间创建索引
  41. unique_for_month
  42. unique_for_year
  43. 联合索引
  44. class Meta:
  45. unique_together = () # 联合唯一索引
  46. index_together = () # 联合索引
  47. 参数(对Django Admin):
  48. blank=True 可以为空
  49. verbose_name 显示名称
  50. editable=False 隐藏
  51. help_text 提示信息
  52. choices 下拉框
  53. error_messages 错误信息
  54. validators 自定义正则表达式
  55. -------------------
  56. error_messages={'c1': '优先错误1', 'c2': '优先错误2', 'c3': '优先错误3'}
  57. validators = [
  58. RegexValidator(regex='root_\d+', message='错了', code='c1'),
  59. RegexValidator(regex='root_a\d+', message='又错了', code='c2'),
  60. RegexValidator(message='又又错了', code='c3'),
  61. ]
  62. -------------------

在模板中实现显示choices的文本

  1. # 使用 get_xxx_display 方法 xxx为字段名
  2. {{ obj.get_sex_display }} {{ obj.sex }}

ORM数据操作

单表 增删改查

  1. # 新增
  2. obj = models.UserGroup.objects.create(title='销售部') # obj为新增对象
  3. models.UserInfo.objects.create(user='root', password='12345', age=18, ug_id=1)
  4. # 查找
  5. group_list = models.UserGroup.objects.all() # 查找所有数据
  6. # group_list QuerySet类型 (列表) 里面包含 UserGroup对象
  7. # values()
  8. group_list = models.UserGroup.objects.all().values(可指定字段) # 查找所有数据
  9. # group_list QuerySet类型 (列表) 里面包含 字典
  10. # values_list()
  11. group_list = models.UserGroup.objects.all().values_list(可指定字段) # 查找所有数据
  12. # group_list QuerySet类型 (列表) 里面包含 元组
  13. # 条件查询
  14. models.UserGroup.objects.filter(id=1) # id__gt=1 id>1 id__lt=1 id<1
  15. # 删除
  16. models.UserGroup.objects.filter(id=2).delete()
  17. # 更新
  18. models.UserGroup.objects.filter(id=2).update(title='IT部')

进阶操作

  1. # 排序 order_by('-id', 'name') => order by id desc, name
  2. models.UserInfo.objects.all().order_by('-id', 'name') # - 降序
  3. # 分组 聚合函数 annotate
  4. from django.db.models import Count,Sum,Max,Min
  5. res = models.UserInfo.objects.values('ut_id').annotate(c=Count('id'))
  6. res.query # 查看生成的SQL语句
  7. # SELECT ut_id, COUNT(id) AS c FROM app01_userinfo GROUP BY ut_id
  8. # having filter在annotate后面为having,在前面则为where
  9. models.UserInfo.objects.values('ut_id').annotate(c=Count('id')).filter(c_gt=2)
  10. # filter 条件 where, having
  11. models.UserInfo.objects.filter(id=1, age=2) # id=1 and age=2
  12. # 多个条件之间是 and 关系, or 使用 Q
  13. """
  14. id__gt = 1 => id>1 # 大于
  15. id__lt = 5 => id<5 # 小于
  16. id__lte = 2 => id<=2 # 小于等于
  17. id__gte = 1 => id>=1 # 大于等于
  18. id__in = [1,2,3] => id in (1,2,3) # in
  19. id__range = [1,4] => id between 1 and 4
  20. name__startswith='xxx' # 以xxx开头
  21. name__contains='xxx' # 包含xxx
  22. """
  23. # 不等于 排除
  24. models.UserInfo.objects.exclude(id=1) # id != 1

高级操作

  1. from django.db.models import F, Q
  2. # F 获取原来值
  3. models.UserInfo.objects.all().update(age=F('age')+1) # 给所有age+1
  4. # Q 构造复杂查询条件 组合搜索 组合条件
  5. # 直接写 or条件
  6. models.UserInfo.objects.filte(Q(id=1) | Q(id=2) ) # id=1 or id=2
  7. # 嵌套组合(推荐)
  8. q1 = Q()
  9. q1.connector = 'OR'
  10. q1.children.append(('id', 1))
  11. q1.children.append(('id', 10))
  12. q1.children.append(('id', 9))
  13. q2 = Q()
  14. q2.connector = 'OR'
  15. q1.children.append(('age__gt', 10))
  16. q1.children.append(('age__lt', 6))
  17. con = Q()
  18. con.add(q1, 'AND')
  19. con.add(q2, 'AND')
  20. models.UserInfo.objects.filte( con )
  21. # (id=1 or id=10 or id=9) and (age>10 or age<6)
  22. # extra 额外查询条件以及相关表,排序
  23. # select select_params 映射
  24. """
  25. select id, (select count(1) from app01_usergroup where id=9 or id<5) as n from app01_userinfo
  26. """
  27. models.UserInfo.objects.all().extra(
  28. select={
  29. 'n': 'select count(1) from app01_usergroup where id=%s or id<%s'
  30. },
  31. select_params=[8,5]
  32. )
  33. # where params 条件 就是where filter()功能
  34. models.UserInfo.objects.extra(
  35. where=['id=%s or id=2', 'name=%s'],
  36. params=[1, 'lishi']
  37. )
  38. # order_by 排序
  39. models.UserInfo.objects.extra(
  40. order_by=['-id', 'age']
  41. )
  42. # table 笛卡尔积
  43. models.UserInfo.objects.extra(
  44. table=['app01_usergroup']
  45. )
  46. """以上可以组合使用"""

执行原生SQL语句

  1. from django.db import connection, connections
  2. cursor = connection.cursor() # 默认连接 default数据库
  3. cursor = connections['default'].cursor() # 连接指定数据库
  4. # 执行SQL语句
  5. cursor.execute('sql语句', 参数)
  6. # 获取结果
  7. cursor.fetchone()
  8. cursor.fetchall()
  9. """使用models对象row()执行sql语句,返回结果为该对象"""

其他

  1. """ distinct 去重 """
  2. # mysql sqlite 中distinct()不能传参数
  3. models.UserInfo.objects.values('nid').distinct()
  4. # PostgreSQL
  5. models.UserInfo.objects.distinct('nid')
  6. # sql: select distinct nid from userinfo
  7. """ reverse 反转 前面必须是order_by"""
  8. models.UserInfo.objects.all().order_by('id').reverse() # reverse后相对于 '-id'
  9. """ only 指定查询的字段"""
  10. models.UserInfo.objects.all().only('id', 'name') # 对象中只可id,name
  11. # 取其他的字段会从新发送sql请求
  12. """ defer 除指定字段外其他字段都获取"""
  13. models.UserInfo.objects.all().defer('name') # 只有name字段没有,如果获取name字段则会从新发送sql请求
  14. """ using 指定数据库 默认是default数据库"""
  15. models.UserInfo.objects.all().using('db2')
  16. """ dates"""
  17. models.UserInfo.objects.dates('ctime', 'day', 'DESC')
  18. """
  19. year, month, day
  20. year: 年-月-01 只有年份 月日填充01
  21. month: 年-月-01 只有年月 日填充01
  22. day: 年-月-日 显示 年-月-日
  23. DESC, ASC
  24. """
  25. """ datetimes"""
  26. """
  27. year,month,day,hour,minute,second
  28. tzinfo 设定时区
  29. pip3 install pytz # 需要安装
  30. import pytz
  31. pytz.all_timezones # 所有时区
  32. pytz.timezone('Asiz/Shanghai') # +8
  33. """
  34. models.UserInfo.objects.datetime('ctime', 'hour', tzinfo=pytz.UTC)
  35. models.UserInfo.objects.datetime('ctime', 'hour', tzinfo=pytz.timezone('Asiz/Shanghai'))
  36. """none 什么都不取"""
  37. """ aggregate 聚合函数 不分组 将整个表作为一组"""
  38. models.UserInfo.objects.aggregate(ug_c=Count('ut_id', distinct=True), u_c=Count('id')) # 对ut_id 进行去重统计 id不去重统计
  39. """ count 计算个数"""
  40. """ get 找到一个正常 找到多个或没有异常"""
  41. """ bulk_create 批量插入"""
  42. objs = [
  43. models.UserInfo(name='a1'),
  44. models.UserInfo(name='a2')
  45. ]
  46. models.UserInfo.objects.bulk_create(objs, 10)
  47. # 10表示一次插入10数据,有100条数据就要分10次插入
  48. """ get_or_create 存在则获取,不存在则参加"""
  49. # obj 数据对象 created bool
  50. obj,created = models.UserInfo.objects.get_or_create(
  51. username='root',
  52. defaults={'u_id':2,...}
  53. ) # 根据username查询, 有返回数据, 没有添加
  54. """update_or_create 有则更新 没有则创建"""
  55. obj,created = models.UserInfo.objects.update_or_create(
  56. username='root',
  57. defaults={'u_id':2,...}
  58. )
  59. """ first 取第一个
  60. last 取最后一个
  61. in_bulk 根据主键进行查询 同in
  62. """

联表操作

Django2.x 关联表必填的 on_delete

on_delete值 删除关联表时操作
None
models.CASCADE 与之关联也删除
models.DO_NOTHING 什么也不做
models.PROTECT 引发错误ProtectedError
SET_NULL 将值设置为null,前提FK字段需要设置null=True
models.SET_DEFAULT 将值设置为FK中default=默认值的值
``
``
  1. on_delete=None, # 删除关联表中的数据时,当前表与其关联的field的行为
  2. on_delete=models.CASCADE, # 删除关联数据,与之关联也删除
  3. on_delete=models.DO_NOTHING, # 删除关联数据,什么也不做
  4. on_delete=models.PROTECT, # 删除关联数据,引发错误ProtectedError
  5. # models.ForeignKey('关联表', on_delete=models.SET_NULL, blank=True, null=True)
  6. on_delete=models.SET_NULL, # 删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空,一对一同理)
  7. # models.ForeignKey('关联表', on_delete=models.SET_DEFAULT, default='默认值')
  8. on_delete=models.SET_DEFAULT, # 删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值,一对一同理)
  9. on_delete=models.SET, # 删除关联数据,
  10. a. 与之关联的值设置为指定值,设置:models.SET(值)
  11. b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)

正向操作

  1. user = models.UserInfo.objects.all().first() # 获取一条数据
  2. user.ut.title # 自动进行跨表获取 ut是FK字段 会发送SQL查询请求
  3. # 使用values时结果不能跨表 只能在查询是跨表 FK字段名__跨表字段名
  4. users = models.UserInfo.objects.all().values('id', 'name', 'ut__title')
  5. # 查询时主动连表 (数据量少)
  6. users = models.UserInfo.objects.all().select_related('ut')
  7. # 不做连表查询,分两次查询 (数据量大)
  8. models.UserInfo.objects.all().prefetch_related('ut')

反向操作

使用:小写表名_set

  1. group = models.UserGroup.objects.all().first()
  2. # 获取当前组下所有user
  3. group.userinfo_set.all() # 自动反向关联
  4. # 一对一时OneToOne 无需加_set 也没有all()方法
  5. group.userinfo.name
  6. # ForeignKey() 中 添加参数 related_query_name = 'xx'
  7. # 则反向查询时 xx_set
  8. # ForeignKey() 中 添加参数 related_name = 'xx'
  9. # 则反向查询时 直接 .xx 获取

Django 2.x 中的ForeignKey

  1. # Django 2.0 中 foreignkey必须添加on_delete参数
  2. # 不加则报 以下错误
  3. # TypeError: __init__() missing 1 required positional argument: 'on_delete'
  4. user = models.ForeignKey(User, on_delete=models.CASADE)

OneToOne

ForeignKey + unique

  1. user = models.OneToOneField(to='UserInfo', to_field='id')

多对多

自定义第三张表

  1. class Boy(models.Model):
  2. name = models.CharField(max_length=32)
  3. class Girl(models.Model):
  4. nick = models.CharField(max_length=32)
  5. class Love(models.Model):
  6. b = models.ForeignKey('Boy')
  7. g = models.ForeignKey('Girl')
  8. # 联合唯一索引
  9. class Meta:
  10. unique_together = [
  11. ('g', 'b'),
  12. ]
  13. -----------------------------------------
  14. # 得到指定男孩有关系的女孩
  15. boy = models.Boy.objects.filter(name='张三').first()
  16. love_list = boy.love_set.all() # 反向拿到 love
  17. for row in love_list:
  18. row.g.nick # 得到女孩
  19. # 跨表
  20. love_list = models.Love.objects.filter(b__name='张三')
  21. for i in love_list:
  22. i.b.nikc # 没循环一次,跨表查询一次
  23. # 查询时跨表 (推荐)
  24. # 结果是字典
  25. girls = models.Love.objects.filter(b__name='张三').values('g__nick')
  26. # 结果是对象
  27. girls = models.Love.objects.filter(b__name='张三').select_related('g')

Django自动生成第三张表 ManyToManyField

  1. """
  2. 自动生成的第三张表只能有3列 id boy_id girl_id
  3. 如果对第三张表没有其他字段要求,可使用自动生成
  4. """
  5. class Boy(models.Model):
  6. name = models.CharField(max_length=32)
  7. # 放在boy 和 girl中都相同, 不能直接操作第三张表
  8. m = models.ManyToManyField('Girl') # 会自动生成 app01_boy_m 表
  9. class Girl(models.Model):
  10. nick = models.CharField(max_length=32)
  11. ----------------------------------------
  12. boy = models.Boy.objects.filter(name='张三').first()
  13. boy.m.add(2) # 增加 boy和id为2的girl关系 参数可写多个
  14. boy.m.remove(1) # 删除
  15. boy.m.set([1,]) # 重置,先清空再添加
  16. boy.m.all() # 结果 QuerySet 中为girl对象
  17. boy.m.filter(nick='小计') # 赛选, 只能是girl中的字段
  18. boy.m.clear() # 清空和boy相关的记录
  19. # 反向
  20. girl = models.Girl.objects.filter(nick='小计').first()
  21. girl.boy_set.all() # 得到和girl相关的

ManyToManyField + 自定义第三张表

  1. class Boy(models.Model):
  2. name = models.CharField(max_length=32)
  3. m = models.ManyToManyField('Girl',
  4. through='Love',
  5. through_fields=('b','g')
  6. ) # 指定使用Love为第三表,不自动创建,
  7. class Girl(models.Model):
  8. nick = models.CharField(max_length=32)
  9. class Love(models.Model):
  10. b = models.ForeignKey('Boy')
  11. g = models.ForeignKey('Girl')
  12. """不能使用 add remove set """

函数

内置函数可使用extra实现

from django.db.models import functions

内置时间函数

  1. # 只获取时间的yera
  2. models.Article.objects.annotate(ct=functions.Extract('create_time', 'YEAR_MONTH')) # 201809
  3. models.Article.objects.annotate(ct=functions.ExtractYear('create_time'))
  4. models.Article.objects.annotate(ct=functions.Trunc('create_time', 'YEAR')) #
  5. # 内置函数不灵活, 使用extra()
  6. models.Article.objects.extra(select={'ct': 'date_format(create_time, "%%Y-%%m")'}).values('ct')

内置函数

  1. # Cast 类型转换
  2. models.Article.objects.annotate(c=functions.Cast('id', FloatField()))
  3. # Coalesce
  4. models.Article.objects.annotate(c=functions.Coalesce('title', 'name')) # 如果title不为空则c = title 如果title为空则c=name
  5. # Concat 拼接字段
  6. models.Article.objects.annotate(c=functions.Concat('title', 'name', '更多的字段...')) # 拼接指定字段
  7. models.Article.objects.annotate(c=functions.Concat('title', Value('-') 'name')) # 拼接指定字段, 常量用value
  8. # Greatest() 获取较大值 Least() 获取较小值
  9. # Length() 长度
  10. # Lower() Upper() 大小写转换
  11. # Now() 当前时间
  12. # substr('字段名', 起始位置, 长度) 子序列

自定义函数

  1. from django.db.models.functions.base import Func
  2. class YearMonthFunc(Func):
  3. function = 'DATE_FORMAT'
  4. template = '%(function)s(%(expressions)s, "%%Y-%%m")'
  5. def __init__(self, expression, **extra):
  6. expressions = [expression]
  7. super(YearMonthFunc, self).__init__(*expression, **extra)

事务

  1. from django.db import transaction
  2. try:
  3. # 开启事务
  4. with transaction.atomic():
  5. # 数据库操作1
  6. # 数据库操作2
  7. except Exception as e:
  8. pass

Django 使用 mysqlclient

django2.2后不能使用pymysql包,推荐使用mysqlclient,使用pymysql包会报错版本过低

依赖安装

  • Ubuntu: sudo apt-get install python3-dev default-libmysqlclient-dev
  • CentOS: sudo yum install python3-devel mysql-devel
  • macOS: brew install mysql-connector-c

Mac OS 需修改

  1. 修改 /usr/local/bin/mysql_config 文件
  2. # on macOS, on or about line 112:
  3. # Create options
  4. libs="-L$pkglibdir"
  5. libs="$libs -l "
  6. 该为
  7. # Create options
  8. libs="-L$pkglibdir"
  9. libs="$libs -lmysqlclient -lssl -lcrypto"

安装

pip install mysqlclient

Mac OS 安装问题

library not found for -lssl

  1. ld: library not found for -lssl
  2. clang: error: linker command failed with exit code 1 (use -v to see invocation)
  3. error: command 'gcc' failed with exit status 1

解决办法:env LDFLAGS="-I/usr/local/opt/openssl/include -L/usr/local/opt/openssl/lib" pip install mysqlclient

zippered unknown enumerated scalar

  1. ld: malformed file
  2. /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/lib/libSystem.tbd:4:18: error: unknown enumerated scalar
  3. platform: zippered
  4. ^~~~~~~~
  5. file '/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/lib/libSystem.tbd'
  6. clang: error: linker command failed with exit code 1 (use -v to see invocation)
  7. error: command 'gcc' failed with exit status 1

解决办法:将xcode更新到最新版本