ORM操作
参考: http://www.cnblogs.com/wupeiqi/articles/5246483.html
1:根据类自动创建数据库表,(类创建文件:models.py)
2:根据类对数据库表中的数据进行各种操作
创建类
a:先写类
# 创建的表名为:cmdb_userinfo
class UserInfo(models.Model):
# 生成表时候会自动创建id列,此列为自增,主键
# 用户名列,字符串类型,指定长度
# 字段类型包含:字符串,数字,时间,二进制
# 字段的参数:
字段参数:
null=True, # db是否可以为空
default='1111', # 默认值
db_column # 指定表中的列的名称
db_index=True, # 在当前字段建立索引
unique=True, # 唯一索引
unique_for_date # 对时间做索引
unique_for_month # 对月份做索引
unique_for_year # 对年份做索引
max_length=xxx # 表示字符长度
primary_key= True # 主键
auto_now # 更新时,自动更新为当前时间
注意:这里的更新需要特定的条件,写法如下:
obj = UserGroup.objects.filter(id=1).first()
obj.caption = 'CEO'
obj.save()
以下这种写法不会生效:
UserGroup.objects.filter(id=1).update(caption='CEO')
auto_now_add # 创建时,自动生成时间
DjangoAdmin提供的参数:
verbose_name Admin页面中显示的字段名称
blank=true Admin页面数据库中是否允许用户输入为空
editable=true Admin页面中是否可以编辑字段,false的话将不显示字段
help_text Admin中该字段的提示信息
choices Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作,避免连表查询。
如:user_type_choices=(
(1,'超级用户),
(2,'普通用户),
(3,'来宾用户),
)
user_type_id = models.IntegerField(choices=user_type_choices,default=1)
这样在页面上显示的此项数据是个选择框显示
error_messages 自定义错误信息(字典类型),从而定制想要显示的错误信息;
字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date
如:{'null': "不能为空.", 'invalid': '格式错误'}
validators 自定义错误验证(列表类型),从而定制想要的验证规则
username = models.CharField(max_length=32)
password = models.CharField(max_length=64)
# 创建自增列方法:
uid = models.AutoField(primary_key = True)
注意:mysql表里只能有一个自增列
说明:创建列指定类型有:EmailField,URLField,GenericIPAddressField等都是针对admin的web页面使用限制,对于数据库内
全部是CharField类型标识。
b:注册APP,要在setting里添加app名称
c:执行命令:
1:python manage.py makemigrations
2:python manage.py migrate
另:在对原表的字段属性修改后运行上面命令就可以修改表属性
如果对表增加一列后,运行上面命令。默认情况下会出现一个提示,让输入新增加列的默认值,输入完成后在运行即可添加一列。
如果我们不想手工输入值,需要在新增加的列属性中添加 null=True,这样运行命令后即可增加一个空列。
d:注意:django默认连接mysql使用的MysqlDB,python3里没有此模块,要使用pyMysql,需要修改项目下的init文件。
加入如下代码:
import pymysql
pymysql.install_as_MySQLdb()
数据 增/删/改/查
# 创建
# 第一种 -推荐使用
# models.UserInfo.objects.create(username='root',password='123')
# 另一种写法
# dic = {'username':'jack','password':'333'}
# models.UserInfo.objects.create(**dic)
# 第二种
# obj = models.UserInfo(username='root',password='123')
# obj.save()
# 查询
# result = models.UserInfo.objects.all() # 获取表所有数据
# result = models.UserInfo.objects.get(username='root') # 获取单条数据
# result = models.UserInfo.objects.filter(username='root') # 指定条件查询
# result = models.UserInfo.objects.filter(username='root',password='123') # 多条件查询
# result = models.UserInfo.objects.filter(username='root').first() # 从查询结果列表中提取第一个值以obj输出
# result = models.UserInfo.objects.filter(username='root').count() # 查询匹配条件数量
# result = models.UserInfo.objects.exclude(username='root') # 指定条件反向查询(非)
# 这里查到的result也是对象
# # 返回的result是django提供的QuerySet类型。就是个列表,每行数据是个对象,
# # [obj,obj...],对象obj包含(id,username,password)
# print(result)
# for i in result:
# print(i.id,i.username,i.password)
n1 = models.Business.objects.all() # 取所有
# QuerySet类型,内部元素都是对象
n2 = models.Business.objects.all().values('id','caption') # 取固定列
# QuerySet类型,内部元素都是字典
n3 = models.Business.objects.all().values_list('id','caption') # 取固定列
# QuerySet类型,内部元素都是元祖
models.Business.objects.filter(id=1).first()
# 获取到的是一个对象
# 删除
# models.UserInfo.objects.all().delete() # 删除所有
# models.UserInfo.objects.filter(id=3).delete() # 删除所有
# 修改
# models.UserInfo.objects.all().update(password="666") # 修改所有
# models.UserInfo.objects.filter(id=1).update(password='5432') # 修改一条
# obj = models.UserInfo.objects.get(id=1) # 修改一条数据
# obj.password = '123'
# obj.save()
其他补充
# models.UserInfo.objects.filter(id__gt=1) 获取ID大于1的值
# models.UserInfo.objects.filter(id__gte=1) 获取ID大于等1的值
# models.UserInfo.objects.filter(id__lt=1) 获取ID小于1的值
# models.UserInfo.objects.filter(id__lte=1) 获取ID小于等于1的值
# models.UserInfo.objects.filter(id__gt=1,id__lt=10) 获取ID大于1小于10的值
# models.UserInfo.objects.filter(id__in=[11,22,33]) 获取ID等于11,22,33的数据
# models.UserInfo.objects.exclude(id__in=[11,22,33]) 获取ID不等于11,22,33的数据
# models.UserInfo.objects.filter(name__isnull=True) 查询name为空的
# models.UserInfo.objects.filter(name__contains='ven') 查询name名称包含ven的值
# models.UserInfo.objects.exclude(name__contains='ven') 查询name名称不包含ven的值
# models.UserInfo.objects.filter(name__icontains='ven') 不区分大小写,功能根据具体数据库而定
# models.UserInfo.objects.filter(id__range=[1,10] 范围查询,查询ID在1到10之间的数据,还有startswith,endswith
# models.UserInfo.objects.filter(name='seven').order_by('id') 正向排序,asc
# models.UserInfo.objects.filter(name='seven').order_by('-id') 反向排序,desc
# models.UserInfo.objects.all()[10:20] 进行分页,就是切片
# models.UserInfo.objects.get(name__regex-r'^(An?|The) +') regex正则匹配,iregex不区分大小写
# models.UserInfo.objects.filter(pub_date__date=datetime.date(2005,1,1)) 匹配日期查找
# models.UserInfo.objects.filter(pub_date__date__gt=datetime.date(2005,1,1)) 大于匹配日期查找
# models.UserInfo.objects.filter(pub_date__year=2005) 匹配年
# models.UserInfo.objects.filter(pub_date__month=12) 匹配月
# models.UserInfo.objects.filter(pub_date__day=3) 匹配日
# models.UserInfo.objects.filter(pub_date__week_day=2) 匹配星期
# models.UserInfo.objects.filter(timestamp__hour=23) 匹配小时
# models.UserInfo.objects.filter(timestamp__minute=29) 匹配分钟
# models.UserInfo.objects.filter(timestamp__second=31) 匹配秒
from django.db.models import Count(个数),Min(最小),Max(最大),Sum(总和)
models.Tbl.objects.filter(c1=1).values('id').annotate(c=Count('num')) 分组操作,filter(c1=1)到这里为第一步筛选,之后是
根据values('id')进行分组,最后c=Count('num')是获取每个组的个数
# models.UserInfo.objects.only('id','name') 仅执行一次查询获取id和name列,
# models.UserInfo.objects.defer('id','name') 仅执行一次查询排除id和name列,
# models.UserInfo.objects.all().order_by('-nid').reverse() 当order_by,reverse同时存在则倒序
using() 指定使用数据库,参数为别名(setting中设置),可用作数据库读写分离。
querySET补充额外的操作方法
extra:构造额外的查询条件或者映射,如:子查询
def extra(self,select=None,where=None,param=None,tables=None,order_by=None,select_params=None)
tablename.object.filter().extra(select={'cid':1})
tablename.object.filter().extra(select={'cid':"%s"},select_params=[1])
tablename.object.filter().extra(select={'nid':"select col from tbl where oth=%s"},select_params=1)
tablename.object.filter().extra(select={'nid':"func(id)"})
tablename.object.filter().extra(where=['headline=1','nid>1']) # 这2个条件以and联合
tablename.object.filter().extra(where=['headline=1 or nid=1']) # 这2个条件以and联合
tablename.object.filter().extra(where=['func(ctime)=1 or nid=%s'],param=['1']) # 加入函数
Django数据库优化:
与性能相关的2个方法:select_related(跨表查询数据只一次性),prefetch_related(数据库查询执行2次)
1:select_related
users = models.User.object.all() 跨表查
for row in users:
print(row.user)
print(row.ut.name)
# 这样性能较差,假如10行数据第一次查询执行了1次数据库操作,在循环里每次到ut.name跨表查询时候都要执行一次数据库操作,
# 这样,一共下来得执行11次数据库操作。优化写法:models.User.object.all().select_related('ut'),这样就只发一次数据库请求,
# 参数只能指定ForignKey字段,当有多个外键字段时候,通过指点外键,将只查询指定字段的关联数据。
users = models.User.object.all().values('user','ut__name')
# 这种方式取回的是个字典,就不可以使用querySet功能了。这也是一个缺点。
2:prefetch_related #2次查询会生成2张表,django会做2张表的关系,提取数据写法不变。
users = models.User.object.filter(id__gt=30).prefetch_related('ut')
# 第一次查询:select * from user where id > 30 获取结果ut_id=[1,2]
# 第二次查询:select * from usertype where id in [1,2] 匹配id为1或2 的数据类型
for row in users:
print(row.name)
print(row.ut.name)
dates(field_name,kind,order='ASC':截取指定时间内容
kind: year(年),month(年月),day(年月日)
models.DatePlus.objects.dates('ctime','day','DESC') 第一个参数:列名,第二个参数是指定截取内容(比如时间数据包含年月日时分秒,
这里使用day,就会进行截取到年月日为止,可选参数:year,month,day),第三个参数:排序(ASC,DESC)
datetimes(field_name,kind,order='ASC',tzinfo=None):截取指定时间内容,并将时间转换为时区时间
kind:year,month,day,hour,minute,second
tzinfo: 时区对象
models.DatePlus.objects.datetimes('ctime','hour',tzinfo=pytz.UTC)
models.DatePlus.objects.datetimes('ctime','hour',tzinfo=pytz.timezone('Asia/Shanghai'))
需要安装个时区模块(pytz);import pytz / pytz.all_timezone / pytz.timezone('...')
raw(raw_query,params=None,translations=None,using=None):执行原生的sql语句
models.User.object.raw('select * from User') 输出的是多个对象,每列数据全部封装到对象里
models.User.object.raw('select nid as id from User2') 将user2中的nid列赋值给user表的id
通过对应关系进行赋值,如先定义一个字典:dic={'id':'nid','name':'username'}
models.User.object.raw('select * from User2',dic) # 通过字典做映射
注意:映射必须要有主键
models.User.object.raw('select * from User',using='default 指定数据库')
aggregate:整个表整体做聚合
from django.db.models import Count(数量),Avg,Max,Min,Sum(数据总和)
models.User.objects.aggregate(n=Count('nid',distinct=True(这个功能是去重))) 求表中nid列所有数据的个数总和
bulk_create:批量插入。 参数batch_size=None 表示一次插入的数量
objs={ models.ddd(name='r1'),models.ddd(name='r2')}
models.DDD.objects.bulk_create(objs,10) # 一次插入10条数据
get_or_create(default=None,**kwargs):如果存在则获取,不存在则创建
obj,created = models.User.objects.get_or_create(uname='root',default={'email':'1@mail.com','u_id':2}
这里的default是当创建的时候使用此参数,查询的时候是调用uname即可。返回2个值,第一个是返回的对象,第二个是状态。
update_or_create(default=None,**kwargs):如果存在则更新,否则,创建
models.User.objects.get_or_create(uname='root',default={'email':'1@mail.com','u_id':2}
in_bulk:根据主键ID进行查找
exists:是否有结果。
外键:(一对多)
现有表:user 和 表:group
在表user 增加外键如下:
usergroup = models.ForeignKey('group 表group名称',to_field='id group表的唯一键',default=1 当创建用户的时候,指定用户的默认组)
简单说明:user表的外键usergroup 就是封装了group表,调用方式;
user.usergroup == group表queryset对象
user.usergroup.id == group.id 等等
如果group表也有外键关联其他表,调用关系是一样的,如:
user.usergroup.group外键.关联表的字段名
增/删/该/查同上
1:载入页面提取组信息:grouplist = models.group.objects.all()
2:页面输入数据选择组后提交
3:后台获取选择的组ID后写库
models.user.objects.create(....usergroup=组ID)
# 外键通过点 . 进行跨表查询
一对多跨表操作的3种方式
v1 = models.Host.objects.filter(nid__gt=0)
# 这里通过Print取值使用点.进行跨表取值
v2 = models.Host.objects.filter(nid__gt=0).values('nid','hostname','b_id','b__caption')
# 进行跨表查询是通过双下划线__ 进行
v3 = models.Host.objects.filter(nid__gt=0).values_list('nid','hostname','b_id','b__caption')
# 进行跨表查询是通过双下划线__ 进行
多对多:
创建多对多:
方式一:自定义关系表,关联表可以自定义多列。
class host(models.Model):
nid=models.AutoField(primary_key=True)
hostname=models.CharField(max_length=32,db_index=True)
ip=models.GenericIPAddressField(protocol='both/ipv4',db_index=True)
port=models.IntegerField()
b = models.ForeignKey('Business',to_field='id')
class Application(models.Model):
name = models.CharField(max_length=32)
class HostToApp(models.Model):
hobj=models.ForeignKey(to='host',to_field='nid')
aobj=models.ForeignKey(to='Application',to_field='id')
关联表添加数据方式:
HostToApp.objects.create(hobj_id=1,aobj_id=2)
方式二:自动创建关系表,生成的关联表只有3列生成。
class host(models.Model):
nid=models.AutoField(primary_key=True)
hostname=models.CharField(max_length=32,db_index=True)
ip=models.GenericIPAddressField(protocol='both/ipv4',db_index=True)
port=models.IntegerField()
b = models.ForeignKey('Business',to_field='id')
class Application(models.Model):
name = models.CharField(max_length=32)
r=models.ManyToManyField("host")
# 无法直接对第三张关联表操作
obj = Application.objects.get(id=1)
obj.name
# 第三张表操作添加
obj.r.add(1) # 第三张表添加关联 1对1
obj.r.add(2,3,4) # 第三张表添加关联 1对2,1对3,1对4
obj.r.add(*[1,2,3,4]) ## 第三张表添加关联 1对1,1对2,1对3,1对4
# 第三张表操作删除
obj.r.remove(1)
obj.r.remove(2,3,4)
obj.r.remove(*[1,2,3,4])
obj.r.clear() # 删除applicaton id=1的所有对应关系
# 第三张表操作修改
obj.r.set([3,5,7]) # 将数据库里application id=1的所有对应关系全部修改为1对3,1对5,1对7
# 第三张表操作查询,
obj.r.all() # 获取到的是所有相关的主机对象"列表",queryset