13.Django之数据库models&orm初探(一)

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介:

一、使用django orm的准备操作。
django 默认支持sqlite,mysql, oracle,postgresql数据库。
在默认情况下django的项目中会默认使用sqlite数据库,在打开settings里有如下设置:
13.Django之数据库models&orm初探(一)

当我们想改为mysql数据库时,需要在settings.py中做以下修改。
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'test_db', #数据库名称
'USER': 'root', #连接mysql时使用的用户名
'PASSWORD': '123456', #连接mysql使用的密码
'HOST': '127.0.0.1', #mysql的ip
'PORT': '3306', #连接mysql的端口。
}
}

当我们把连接数据的配置设置完成后,重新启动django项目,这时会报错!
no module named MySQLdb
这是因为django默认你导入的操作mysql的模块是MySQLdb,可是MySQLdb对于py3有很大问题,所以我们需要的模块是PyMySQL。

那么如何解决呢?
首先,要找到项目目录下的init.py文件。
然后在这个文件里面写两行代码:
import pymysql
pymysql.install_as_MySQLdb()
然后,这个报错就会解决。
(如果依旧报错。。。请检查你的pymsql是否有安装。。。)

二、在表(模型)创建之前,需要了解的概念。
首先我们先来假定下面这些概念,字段和关系。

(1)一对一关系:
假如说,一个数据库有两张表,其中一个表是作者的名字,另外一张表则是作者的详细信息。
第一张表中保存有作者的姓名,第二张表则保存了,作者的详细信息,性别,年龄,email等。
在这里,作者的名字和作者的详细信息就是一种一对一的关系,所以说,这种一对一的关系也没必要拆分成两张表。

(2)多对多关系:
拿出版商进行举例,假如说出版商的数据在一张表中,这里面包含出名称,地址,所在城市,省,国家和网站。
书籍信息中包含的书名和出版日期,但是一本书,可能会有多个作者,但是一个作者又可以写多本书。
所以说,多对多的关系就好像作者与书籍之间的关系。

(3)一对多关系:
比如一本书只能被一个出版商出版,但是一个出版商可以出版很多本书,所以说,书籍对出版商来说,就是一对多关系。
这种一对多的关系,也被称为外键。

三、关于表的创建。
models.py
class UserGroup(models.Model):
uid = models.AutoField(primary_key=True)
caption = models.CharField(max_length=32,unique=True)
ctime = models.DateTimeField(auto_now_add=True, null=True)
uptime = models.DateTimeField(auto_now=True, null=True)

class UserInfo(models.Model):

id列,自增,主键

# 用户名列,字符串类型,指定长度
# 字符串、数字、时间、二进制
username = models.CharField(max_length=32,blank=True,verbose_name='用户名')
password = models.CharField(max_length=60, help_text='pwd')
email = models.CharField(max_length=60)
test = models.EmailField(max_length=19,null=True,error_messages={'invalid': '请输入密码'})
#user_group_id 数字
user_group = models.ForeignKey("UserGroup",to_field='uid') # (uid,catption,ctime,uptimew)
user_type_choices = (
    (1, '超级用户'),
    (2, '普通用户'),
    (3, '访客'),
)
user_type_id = models.IntegerField(choices=user_type_choices,default=1)

上面这段代码,每个数据模型都是django.db.models.Model的子类,它的父类Model包含了所有必要的和数据库交互的方法。
其次每个模型相当于单个数据库表(多对多关系例外,会多生成一张关系表),每个属性也是这个表中的字段。属性名就是字段名,它的类型(例如CharField)相当于数据库的字段类型(例如varchar)。大家可以留意下其它的类型都和数据库里的什么字段对应。

然后在仔细思考下,前面说的到的三种关系:
分别是一对一,一对多,多对多。
一对一:实现一对一的本质,就是在外键,(author_id就是foreign key)的关系基础上,给外键加了一个UNIQUE=True的属性;

一对多:就是主外键关系;(foreign key)

多对多:自动创建第三张表(当然我们也可以自己创建第三张表:两个foreign key。

四、orm之基本的增删改查。
(1)增:
from app01.models import *

#create方式一: Author.objects.create(name='kodakumi')

#create方式二: Author.objects.create(**{"name":"hamasakiayumi"})

!!注意!当使用到mysql innodb的事物特性的时候,就要使用save的方式插入记录了。!!

#save方式一: author=Author(name="amuro")
author.save()

#save方式二: author=Author()
author.name="amuro"
author.save()

(2)删:
models.UserInfo.objects.filter(username="amuro").delete()

(3)改:
models.UserInfo.objects.filter(id=3).update(password="130")

--------------- save方法---------
obj=models.UserInfo.objects.filter(id=3)[0]
obj.password = '130'
obj.save()

(4)查:

#result = models.UserInfo.objects.all() #列出表所有记录,返回一个QuerySet类型。

!!在这里简单介绍一下什么是Queryset类型!
在这里,我们可以把Queryset理解为一个列表,这个列表中有很多对象,每个对象就是数据库中的每一条数据!!

#result = models.UserInfo.objects.filter(username='root',password='123') #按条件查询
    查询相关API如下:
    【1】filter(**kwargs):      它包含了与所给筛选条件相匹配的对象。
    filter方法的参数补充:
    #在这以age列做例子:
    age_gt = 1 #age大于1的。
    age_lt = 1 #age小于1的。
    age_lte = 1 #age小于等于1
    age_gte = 1 #age大于等于1
    age_in = [1,2,3] # 找出age为1或2或3的(只要列表中有的就可以)
    age_range = [1,2]#age为这个范围的。
    age_startwith = 'xxx' #age列以xxx开头的
    age_contains = 'xxx' #包含xxx的。2】all():                 查询所有结果。
    【3】get(**kwargs):         返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。

#===============================#
下面是对查询结果进行处理的API
【1values(field):        返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列 model的实例化对象,而是一个可迭代的字典序列.
需要特别注意!!values这个方法可以用来分组!!

values 可以取表中所有记录中的某一个或多个列的数据。
例如:
v1 = models.UserInfo.objects.values('name') #select UserInfo.name from UserInfo
print (v1.query) #获取到生成的sql语句。
select app01_UserInfo.name from UserInfo

!!通过values方法然后通过.annotate进行组合!
from django.db.models import Count
v2 = models.UserInfo.objects.values('name').annotate(count_num=Count('id'))
print (v2.query)
#select 'app01_UserInfo'.'id',COUNT('app01_UserInfo'.id) as "count_num" from "app01_UserInfo" group by 'app01_UserInfo'.id'

!!组合后的查询结果,还可以通过filter方法来进行筛选!

from django.db.models import Count
v2=models.UserInfo.objects.values('name').annotate(count_num=Count('id')).filter(count_num = 2)
!#筛选出count_num = > 2 的记录。
print (v2.query)
#select 'app01_UserInfo'.'id',COUNT('app01_UserInfo'.id) as "count_num" from "app01_UserInfo" group by 'app01_UserInfo'.id' having count ('app01_UserInfo'.id')> 2
#!也就是说把filter放在后面,出现的是sql语句中的having!!

【2】order_by(*field):      对查询结果排序。
例:
user_list = models.UserInfo.objects.all().order_by('id') #以id列为基准从小到大排序。
user_list = models.UserInfo.objects.all().order_by('-id') #以id列为基准从大到小逆向排序。
    user_list = models.UserInfo.objects.all().order_by('-id','name') #以id列为基准从大到小逆向排序,当id列有值重复时,按照name从小到大排序。

【3】reverse() :对查询的结果进行反向排序。
【4】distinct(): 从结果中删除重复的记录。
【5】values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列。
【6】count(): 返回数据库中匹配查询(QuerySet)的对象数量。
【7】first(): 返回第一条记录
【8】last(): 返回最后一条记录
【9】exists(): 如果QuerySet包含数据,就返回True,否则返回False。

单表条件查询:
models.Tb1.objects.filter(id=10,name='test') #找出id=10 并且name字段为test的记录 。
!########下面是神奇的双(下划线)!########
models.Tb1.objects.filter(id
lt=10, idgt=1) # 获取id大于1 且 小于10的值
models.Tb1.objects.filter(id
in=[11, 22, 33]) # 获取id等于11、22、33的数据
models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in

是否为空:
Entry.objects.filter(pub_date__isnull=True)

五、通过外键来实现一对多的示例:
models.py
class Business(models.Model):
#id
caption = models.CharField(max_length=32)

class Host(models.Model):
nid = models.AutoField(primary_key=True)
hostname = models.CharField(max_length=32,db_index=True)
ip = models.GenericIPAddressField(protocol='ipv4',db_index=True)
port = models.IntegerField()
busi = models.ForeignKey(to='Business',to_field='id')#创建外键,这个外键以表Business的id字段为准。
不过需要注意的是,这个busi变量的内容不是某个值,而是一个特殊对象,可以通过这个对象去取到Business表中对应id的记录。!!

当创建好外键关系后,在 Business表中插入了三条数据:
+----+-----------+
| id | caption |
+----+-----------+
| 1 | 运维部 |
| 2 | 开发部 |
| 3 | 测试部 |
+----+-----------+

然后在host表中插入四条主机信息:
+-----+----------+---------------+------+---------+
| nid | hostname | ip | port | busi_id |
+-----+----------+---------------+------+---------+
| 1 | host1 | 192.168.100.1 | 80 | 1 |
| 2 | host2 | 192.168.100.5 | 80 | 1 |
| 3 | host3 | 192.168.100.6 | 80 | 2 |
| 4 | host4 | 192.168.100.7 | 80 | 2 |
+-----+----------+---------------+------+---------+

这时,使用django orm进行联表查询:
views.py:

def host(request):
h1 = models.Host.objects.all()
for row in h1:
print(row.nid,row.hostname,row.ip,row.busi.caption)
return HttpResponse('host')
#busi 带只了另外一张表的一行数据,这就是外键的特性!
结果如下:
1 host1 192.168.100.1 运维部
2 host2 192.168.100.5 运维部
3 host3 192.168.100.6 开发部
4 host4 192.168.100.7 开发部

六、关于F,Q
F:当要对数据库记录做修改的时候,能快速获取到上一个值,来进行操作。
比如:
models.UserInfo.objects.all().update(age=F('age')+1)

Q:用于复杂的条件查询,Q对象(django.db.models.Q)可以对关键字参数进行封装,从而更好地应用多个查询。可以组合使用 &(and),|(or),~(not)操作符,当一个操作符是用于两个Q的对象,它产生一个新的Q对象。
例如:
用法1:
models.UserInfo.objects.filter(Q(id=1)|Q(id__gt=2))
##查找出id为1或者2的记录。

用法2:直接创建一个Q对象。
q1 = Q( ) #首先创建一个Q对象。
q1.connector = 'OR' #Q对象中的查询条件的连接方式。
q1.children.append(('id',1))
q1.children.append(('id',2)) #在Q1这个对象里添加两个查询条件。

更复杂的条件嵌套。
q1 = Q( ) 
q1.connector = 'OR' 
q1.children.append(('id',1))
q1.children.append(('id',2))

q2 = Q( )
q2.connector = 'OR'
q2.children.append(('name','ayu'))
q2.children.append(('name','hamasaki'))

con = Q( )
con.add(q1,'AND')
con.add(q2,'AND')
#最后生成的结果是(id=1 or id=2) and (name=ayu or name=hamasaki)




      本文转自苏浩智 51CTO博客,原文链接:http://blog.51cto.com/suhaozhi/2062636,如需转载请自行联系原作者




相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
9天前
|
关系型数据库 MySQL 数据库
ORM对mysql数据库中数据进行操作报错解决
ORM对mysql数据库中数据进行操作报错解决
33 2
|
20天前
|
存储 关系型数据库 MySQL
【阿里规约】阿里开发手册解读——数据库和ORM篇
从命名规范、建表规范、查询规范、索引规范、操作规范等角度出发,详细阐述MySQL数据库使用过程中所需要遵循的各种规范。
【阿里规约】阿里开发手册解读——数据库和ORM篇
|
6天前
|
数据库 Python
django中数据库外键可以自定义名称吗
django中数据库外键可以自定义名称吗
|
2月前
|
Java 数据库连接 数据库
告别繁琐 SQL!Hibernate 入门指南带你轻松玩转 ORM,解锁高效数据库操作新姿势
【8月更文挑战第31天】Hibernate 是一款流行的 Java 持久层框架,简化了对象关系映射(ORM)过程,使开发者能以面向对象的方式进行数据持久化操作而无需直接编写 SQL 语句。本文提供 Hibernate 入门指南,介绍核心概念及示例代码,涵盖依赖引入、配置文件设置、实体类定义、工具类构建及基本 CRUD 操作。通过学习,你将掌握使用 Hibernate 简化数据持久化的技巧,为实际项目应用打下基础。
66 0
|
2月前
|
数据库 Java 数据库连接
玩转Play Framework的秘密武器:Ebean ORM带你解锁高效数据库操作新姿势,让你的代码从此飞起来!
【8月更文挑战第31天】Play Framework 以其简洁的 API 和高效开发体验著称,Ebean ORM 则是其推荐的对象关系映射(ORM)工具之一。Ebean 可将 Java 对象轻松映射到数据库表,简化数据库交互。本文将指导你在 Play Framework 中使用 Ebean ORM 进行数据库操作,涵盖项目创建、依赖引入、数据库配置、模型定义及 CRUD 操作,并通过示例代码展示实现过程。通过这些步骤,你将学会如何利用 Ebean 的丰富功能,如事务管理、查询构建等,提升 Web 应用的数据库交互能力。
29 0
|
2月前
|
数据库 测试技术 开发者
Play Framework的测试魔法:让代码在舞台上翩翩起舞,确保应用质量的幕后英雄!
【8月更文挑战第31天】Play Framework不仅以其高效开发与部署流程著称,还内置了强大的测试工具,提供全面的测试支持,确保应用高质量和稳定性。本文将详细介绍如何在Play Framework中进行单元测试和集成测试,涵盖`WithApplication`、`WithServer`及`WithDatabase`等类的使用方法,并通过示例代码手把手教你如何利用Play的测试框架。无论是单元测试、集成测试还是数据库操作测试,Play Framework均能轻松应对,助你提升应用质量和开发效率。
28 0
|
2月前
|
SQL 关系型数据库 数据库连接
Entity Framework Core 入门教程来袭!快速上手强大的 ORM 工具,开启高效数据库开发之旅!
【8月更文挑战第31天】Entity Framework Core(EF Core)是一个轻量且可扩展的对象关系映射(ORM)框架,允许开发者使用 .NET 语言操作数据库而无需直接编写 SQL 语句。本教程涵盖 EF Core 的安装、数据库上下文创建、数据库连接配置及常见数据库操作(如添加、查询、更新和删除),并介绍如何利用数据库迁移功能安全地更改数据库结构。通过本教程,你可以快速掌握 EF Core 的基本用法,提高开发效率。
37 0
|
2月前
|
API 数据库 开发者
【独家揭秘】Django ORM高手秘籍:如何玩转数据模型与数据库交互的艺术?
【8月更文挑战第31天】本文通过具体示例详细介绍了Django ORM的使用方法,包括数据模型设计与数据库操作的最佳实践。从创建应用和定义模型开始,逐步演示了查询、创建、更新和删除数据的全过程,并展示了关联查询与过滤的技巧,帮助开发者更高效地利用Django ORM构建和维护Web应用。通过这些基础概念和实践技巧,读者可以更好地掌握Django ORM,提升开发效率。
22 0
|
2月前
|
关系型数据库 MySQL 机器人
Django入门到放弃之数据库配置
Django入门到放弃之数据库配置
下一篇
无影云桌面