源码:https://blog.csdn.net/feifeiyechuan/article/details/84940951
目录
四、Django ORM模型一对一、一对多、多对多的操作详解
一、DjangoORM的配置及创建
1、ORM简介
ORM:(object relational mapping)关系对象映射。定义一个类自动生成数据库的表结构。
创建数据库的时候,一般有以下几种常用数据类型:数字、字符串以及时间。
ORM分为两种:
- DB First 数据库里先创建数据库表结构,根据表结构生成类,根据类操作数据库
- Code First 先写代码,执行代码创建数据库表结构
主流的orm都是code first。django 的orm也是code first,所以学的时候,本质就分为两块:
- 根据类自动创建数据库表
- 根据类对数据库表中的数据进行各种操作
2、配置文件
- 配置显示sql语句:
项目settings.py文件中:
LOGGING = {
'version':1,
'disable_existing_loggers':False,
'handlers':{
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers':{
'django.db.backends':{
'handlers':['console'],
'propagate':True,
'level':'DEBUG'
},
}
}
- 配置数据库mysql
项目settings.py文件中:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', #连接数据库种类
'NAME': 'test02_1209', #数据库名,****记得提前创建该数据库****
'USER': 'root', #用户名
'PASSWORD': 'root', #密码
'HOST': '127.0.0.1', #登陆主机
'PORT': '3306', #登陆端口
}
}
同时在项目__init__.py文件中:
原因是在Django中操作数据库是通过名字MySQLdb来识别的,但是python3中用的是pymysql,保证了Django的正确识别。
import pymysql
pymysql.install_as_MySQLdb()
- 注册app
项目settings.py文件中:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# 'usermange.apps.UsermangeConfig', #pycharm自动生成,与下一行一样的作用
'usermange', #添加app,和上一行一样的意思
]
3、创建数据模型
在usermange应用下的models.py文件中:
from django.db import models
# Create your models here.
class UserInfo(models.Model):
id = models.AutoField(primary_key=True)
uname = models.CharField(max_length=20)
uage = models.IntegerField()
ucdate = models.DateField(auto_now_add=True)
umdate = models.DateField(auto_now = True)
4、生成表结构
在命令行中执行命令生成表结构:
python manage.py makemigrations #生成migrations临时文件
python manage.py migrate #根据生成的migrations直接生成数据库表结构
#后续每次如果更改了表结构,按顺序执行这两条命令即可
二、Django ORM增删改查
1、数据的添加
#方法一:
UserInfo(uname='gaofei',uage=11).save()
# 方法二
userobj = UserInfo()
userobj.uname = 'zhang3'
userobj.uage = 22
userobj.save()
# 方法三
UserInfo.objects.create(uname='li4',uage=23)
#方法四
userobj1 = UserInfo.objects.get_or_create(uname='wang5', uage=24,default={'uname':'z6','uage':22})
print(userobj1)
#(<UserInfo: UserInfo object (4)>, True)
#如果通过前面的条件没有找到数据,那么新建一条记录,记录的字段赋值为default中的参数,返回(新建的对象,True)
# (< UserInfo: UserInfo object (4) >, False) #如果通过前面的条件查找到了一条数据,返回(该对象,False)
# 方法五:推荐使用
dicts = {'uname':'gaofeifeifei','uage':'22'}
UserInfo(**dicts).save()
2、数据的修改
#===数据的修改
#批量更新:谨慎使用,如果数据量小最好用单个跟新
UserInfo.objects.filter(id=7).update(uname='gaofeifei')
# 单个更新,自动时间的跟新只支持单个跟新不支持批量跟新
userobj2 = UserInfo.objects.filter(id=7)[0]
userobj2.uname = 'gaofei'
userobj2.save()
#跟新或者创建
userobj3 = UserInfo.objects.update_or_create(uname='li4',uage=23,default='uname':'z6','uage':33})
#和get_or__create类似
#如果通过前面的uname,uage找到一条记录,按照default中的字段值进行修改,返回(跟新后的对象,False)
#如果通过前面的uname,uage找不到记录,新建一条记录按照default中的字段值进行赋值,返回(新建的对象,True)
3、数据的删除
#批量删除,同样谨慎使用,别一失足成千古恨
UserInfo.objects.filter(uname='gaofeifei').delete() #删除满足条件的
UserInfo.objects.all().delete() #删除所有
#单个删除
userobj5 = UserInfo.objects.get(id = 8)
userobj5.delete() #虽然是两句话,但是执行的是一个sql语句
# 执行的sql语句为:
# DELETE FROM `usermange_userinfo` WHERE `usermange_userinfo`.`id` IN(8)
4、数据的查询(重点)
(1)查询所有数据的方法
# 1、---查询所有数据的方法
datas1 = UserInfo.objects.all() #返回类型QquerySet,内部是所有对象的集合
datas2 = UserInfo.objects.values() #返回列表类型,是对象对应字典为元素的列表
print(type(datas1),'==>',datas1)
print(type(datas2),'==>',datas2)
# ----注意,对于返回值类型为QuerySet类型的数据,可以使用切片进行截取数据
print(datas1[2]) #获取下表索引为2的数据对象 使用了sql
print(datas1[1:3]) #获取下表1到3(取左不取右)的对象集合,类型为QuerySets 使用了python内部的排序
print(datas1[1:3:-1]) #倒序输出对象列表 使用了python的倒叙排列
(2)按照条件查询数据
- 返回新QuerySets的API
方法名 解释
- filter() 过滤查询对象。
- exclude() 排除满足条件的对象
- annotate() 使用聚合函数
- order_by() 对查询集进行排序
- reverse() 反向排序
- distinct() 对查询集去重
- values() 返回包含对象具体值的字典的QuerySet
- values_list() 与values()类似,只是返回的是元组而不是字典。
- dates() 根据日期获取查询集
- datetimes() 根据时间获取查询集
- none() 创建空的查询集
- all() 获取所有的对象
- union() 并集
- intersection() 交集
- difference() 差集
- select_related() 附带查询关联对象
- prefetch_related() 预先查询
- extra() 附加SQL查询
- defer() 不加载指定字段
- only() 只加载指定的字段
- using() 选择数据库
- select_for_update() 锁住选择的对象,直到事务结束。
- raw() 接收一个原始的SQL查询
- 具体使用
#--filter
datas3 = UserInfo.objects.filter(uname='li4', uage=23) #获取同时满足参数的数据QuerySet集合
print(type(datas3),'==>',datas3)
#--get
datas4 = UserInfo.objects.get(id = 6) #获取同时满足参数的对象,如果查询结果为空或者有多条数据,报错
dataobj1 = UserInfo.objects.first() #返回第一个对象
dataobj2 = UserInfo.objects.last() #返回最后一个对象
#--exclude
datas5 = UserInfo.objects.exclude(uname='li4') #获取不满足条件的数据QuerySet集合\
#reverse()
datas6 = UserInfo.objects.all().reverse() #获取反转后的结果集,类型为QuerySet,可以进行多次的reverse()
#distinct()
# datas7 = UserInfo.objects.values('uname','id').distinct() #根据uname,id进行去重,返回去重后的QuerySet集合,内部为字典为元素的列表
# print(datas7)
#
# #order_by()
datas8 = UserInfo.objects.all().order_by('id') #根据id进行升序排序 返回结果为QuerySet,对象集合
datas8 = UserInfo.objects.all().order_by('-id') #根据id进行降序配许
#count()
data9 = UserInfo.objects.all().count() # 统计结果数量 #通过sql语句
data9 = UserInfo.objects.values().count()
data9 = UserInfo.objects.count()
#exists()
datas10 = UserInfo.objects.all().exists() #是否查询到数据,这个还是通过sql查询所有数据,如果返回有值为True,否则为False
datas10 = UserInfo.objects.values().exists()
datas10 = UserInfo.objects.filter(id=6).exists()
#values_lists()
datas11 = UserInfo.objects.values_list() #返回的结果集(QuerySet内部为结果元组为元素组成的列表)
- 链式查找
#链式查找
UserInfo.objects.filter(uname__contains='li') #模糊查询
UserInfo.objects.filter(uname__icontains='li') #忽略大小写模糊查询
UserInfo.objects.filter(uname__regex= 'li4$') #正则匹配
UserInfo.objects.filter(uname__iregex= 'li4$') #忽略大小写正则匹配
UserInfo.objects.filter(uname__exact='li4') #全匹配
UserInfo.objects.filter(uname__iexact='li4') #忽略大小写全匹配
UserInfo.objects.filter(uname__startswith='l') #以。。。开头
UserInfo.objects.filter(uname__istartswith='l') #忽略大小写,以。。。开头
UserInfo.objects.filter(uname__endswith='l') #以。。。结束
UserInfo.objects.filter(uname__iendswith='l') #忽略大小写,以。。。结束
UserInfo.objects.filter(uname__in=('i','li4')) #值是否在这个集合中,参数可以是列表,元组,集合
UserInfo.objects.filter(uage__lt=5) # 小于-------------------以下适用数字类型
UserInfo.objects.filter(uage__lte=5) #小于等于
UserInfo.objects.filter(uage__gt=5) #大于
UserInfo.objects.filter(uage__gte=5) #大于等于
UserInfo.objects.filter(uage__range=(11,12)) #在11-12范围内,包含11和12
UserInfo.objects.filter(ucdate__year=2018) #年份是否为2018-----------以下适用日期类型
UserInfo.objects.filter(ucdate__month=12) #月份为12
UserInfo.objects.filter(ucdate__day=10) #日期为10
print(UserInfo.objects.filter(ucdate__week_day= 1) ) #星期一 #the day of week from 1 (Sunday) to 7 (Saturday)
print()
UserInfo.objects.filter(ucdate__hour=12) #12点
UserInfo.objects.filter(ucdate__minute=20) #20分
UserInfo.objects.filter(ucdate__second=10) #10秒
三、ORM字段介绍
1、字段类型
1、models.AutoField 自增列 = int(11)
如果没有的话,默认会生成一个名称为 id 的列,如果要显示的自定义一个自增列,必须将给列设置为主键 primary_key=True。
2、models.CharField 字符串字段
必须 max_length 参数
3、models.BooleanField 布尔类型=tinyint(1)
不能为空,Blank=True
4、models.ComaSeparatedIntegerField 用逗号分割的数字=varchar
继承CharField,所以必须 max_lenght 参数
5、models.DateField 日期类型 date
对于参数,auto_now = True 则每次更新都会更新这个时间;auto_now_add 则只是第一次创建添加,之后的更新不再改变。
6、models.DateTimeField 日期类型 datetime
同DateField的参数
7、models.Decimal 十进制小数类型 = decimal
必须指定整数位max_digits和小数位decimal_places
8、models.EmailField 字符串类型(正则表达式邮箱) =varchar
对字符串进行正则表达式
9、models.FloatField 浮点类型 = double
10、models.IntegerField 整形
11、models.BigIntegerField 长整形
integer_field_ranges = {
'SmallIntegerField': (-32768, 32767),
'IntegerField': (-2147483648, 2147483647),
'BigIntegerField': (-9223372036854775808, 9223372036854775807),
'PositiveSmallIntegerField': (0, 32767),
'PositiveIntegerField': (0, 2147483647),
}
12、models.IPAddressField 字符串类型(ip4正则表达式)(已弃用,用13、)
13、models.GenericIPAddressField 字符串类型(ip4和ip6是可选的)
参数protocol可以是:both、ipv4、ipv6
验证时,会根据设置报错
14、models.NullBooleanField 允许为空的布尔类型
15、models.PositiveIntegerFiel 正Integer
16、models.PositiveSmallIntegerField 正smallInteger
17、models.SlugField 减号、下划线、字母、数字
18、models.SmallIntegerField 数字
数据库中的字段有:tinyint、smallint、int、bigint
19、models.TextField 字符串=longtext
20、models.TimeField 时间 HH:MM[:ss[.uuuuuu]]
21、models.URLField 字符串,地址正则表达式
22、models.BinaryField 二进制
23、models.ImageField 图片
24、models.FilePathField 文件
25、distance_bigger_better_choice = ( # 枚举
(1, '是'),
(0, '不是')
)
distance_bigger_better = models.IntegerField(verbose_name="相似距离是否越大越像", choices=distance_bigger_better_choice)
2、字段参数
null # 是否可以为空
default # 默认值
primary_key # 主键
db_column # 列名
db_index # 索引(db_index=True)
unique # 唯一索引(unique=True)
unique_for_date # 只对日期索引
unique_for_month # 只对月份索引
unique_for_year # 只对年做索引
auto_now # 创建时,自动生成时间
auto_now_add # 更新时,自动更新为当前时间
注意:更新时间的话,需要使用单个更新,不能使用批量更新,因为时间的更新是python增的操作,不是sql的操作。单个更新会把所有的数据进行重新提交。