Django对各种数据库提供了很好的支持,包括:PostgreSQL、MySQL、SQLite和Oracle,而且为这些数据库提供了统一的调用API,这些API统称为ORM框架。通过使用Django内置的ORM框架可以实现数据库连接和读写操作。

构建模型

ORM框架是一种程序技术,用于实现面向对象编程语言中不同类型系统的数据之间的转换。从效果上说,其实是创建了一个可在编程语言中使用的“虚拟对象数据库”,通过对虚拟对象数据库操作从而实现对目标数据库的操作,虚拟对象数据库与目标数据库是相互对应的。在Django中,虚拟对象数据库也称为模型。通过模型实现对目标数据库的读写操作,实现方法如下:

配置目标数据库信息

  1. DATABASES = {
  2. # 'default': {
  3. # 'ENGINE': 'django.db.backends.sqlite3',
  4. # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
  5. # },
  6. # mysql 的配置
  7. 'default': {
  8. 'ENGINE': 'django.db.backends.mysql',
  9. 'NAME': 'django_database', # 你的数据库名
  10. 'USER': 'root', # 你的用户
  11. 'PASSWORD':'abcdef' , # 你的密码
  12. 'HOST': '192.168.43.205' , # 数据库所在IP,
  13. 'PORT': '3306' , # 端口
  14. }
  15. }

如果数据库不能远程,可参考mysql远程访问中的mysql命令改表法,能快速实现。

构建虚拟数据库

  1. from django.db import models
  2. # Create your models here.
  3. class Type(models.Model):
  4. id = models.IntegerField(primary_key=True)
  5. type_name = models.CharField(max_length=20)
  6. class Product(models.Model):
  7. id = models.IntegerField(primary_key=True)
  8. name = models.CharField(max_length=50)
  9. weight = models.CharField(max_length=20)
  10. size = models.CharField(max_length=100)
  11. type = models.ForeignKey(Type, on_delete=models.CASCADE)

在上述例子中,我们创建了数据表index_product和index_type,而表字段是在模型中定义的,在模型Type和Product中定义的字段类型有整型和字符串类型,但在实际开发中,我们需要定义不同的数据类型来满足各种需求,因此Django划分了多种不同的数据类型:
image.png
Django提供的字段类型还会对数据进行正则处理和验证功能等,进一步完善了数据的严谨性。除了表字段类型之外,每个表字段还可以设置相应的参数,使得表字段更加完善。
image.png

虚拟数据库迁移到目标数据库

  1. python manage.py makemigrations
  2. python manage.py migrate

makemigrations指令用于将index所定义的模型生成0001_initial.py文件,该文件存放在index的migrations文件夹,打开查看0001_initial.py文件。
image.png

image.png

数据表间的关系

一个模型对应目标数据库的一个数据表,但我们知道,每个数据表之间是可以存在关联的,表与表之间有三种关系:一对一、一对多和多对多。

一对一关系

在模型中可以通过OneToOneField来构建数据表的一对一关系,代码如下:

  1. class Performer(models.Model):
  2. id = models.IntegerField(primary_key=True)
  3. name = models.CharField(max_length=20)
  4. nationality = models.CharField(max_length=20)
  5. masterprice = models.CharField(max_length=50)
  6. class Performer_Info(models.Model):
  7. id = models.IntegerField(primary_key=True)
  8. performer = models.OneToOneField(Performer, on_delete=models.CASCADE) #一对一
  9. birth = models.CharField(max_length=20)
  10. elapse = models.CharField(max_length=20)

一对多关系

在模型中可以通过ForeignKey来构建数据表的一对多关系,代码如下:

  1. class Program(models.Model):
  2. id = models.IntegerField(primary_key=True)
  3. performer = models.ForeignKey(Performer,on_delete=models.CASCADE)
  4. name = models.CharField(max_length=20)

多对的关系

在模型中可以通过ManyToManyField来构建数据表多的对多关系,代码如下:

  1. class Advertiser(models.Model):
  2. id = models.IntegerField(primary_key=True)
  3. name = models.CharField(max_length=20)
  4. performer = models.ManyToManyField(Performer)

进行数据迁移:

  1. python manage.py makemigrations
  2. python manage.py migrate

image.png

数据表的读写

数据库的读写操作主要对数据进行增、删、改、查。以的数据表index_type和index_product为例,分别在两个数据表中添加下面的数据。
image.png
image.png
为了更好地演示数据库的读写操作,在项目中使用shell模式(启动命令行和执行脚本)进行讲述,该模式主要为方便开发人员开发和调试程序。在PyCharm的Terminal下开启shell模式,输入python manage.py shell指令即可开启:
image.png

插入数据

下面在index_type中插入数据

  1. from index.models import *
  2. t = Type(id=1,type_name='手机')
  3. t.save()
  4. t = Type(id=2,type_name='平板电脑')
  5. t.save()
  6. t = Type(id=3,type_name='智能穿戴')
  7. t.save()
  8. t = Type(id=4,type_name='通用配件')
  9. t.save()
  1. p = Product(id=1,name='荣耀V10',weight='172g',size='157.00*74.98*6.97mm',type_id=1)
  2. p.save()
  3. p = Product(id=2,name='HuaWEI nova2s',weight='169g',size='156.9*75.1*7.5mm',type_id=1)
  4. p.save()
  5. p = Product(id=3,name='荣耀Waterplay',weight='465g',size='248*173*7.8mm',type_id=2)
  6. p.save()
  7. p = Product(id=4,name='荣耀畅玩平板',weight='460g',size='9.8*159.8*7.95mm',type_id=2)
  8. p.save()
  9. p = Product(id=5,name='PORSCHE DESIGN',weight='64g',size='45*48.3*1.6mm',type_id=3)
  10. p.save()
  11. p = Product(id=6,name='华为运动手环',weight='21g',size='44*19.7*10.3mm',type_id=3)
  12. p.save()
  13. p = Product(id=7,name='荣耀移动电源1000mA',weight='210g',size='139*73.7*15.5mm',type_id=4)
  14. p.save()
  15. p = Product(id=8,name='荣耀体脂秤',weight='1850g',size='300*300*23.7mm',type_id=4)
  16. p.save()

更新数据

image.png

删除数据

image.png

查询数据

  1. from index.models import *
  2. #------ 全表查询 ------------
  3. # SQL:select * from index_product,
  4. p = Product.objects.all()
  5. p[1].name
  6. #SQL: select * from index_product LIMIT 5,
  7. p = Product.objects.all()[:5]
  8. #SQL: select name from index_product,
  9. p = Product.objects.values('name')
  10. #------where 查询 ------------
  11. #SQL: select * from index_product where id = 2,
  12. p = Product.objects.get(id=2)
  13. p.name
  14. p = Product.objects.filter(id=2)
  15. p[0].name
  16. #------ and 查询 -----------
  17. #SQL: select * from index_product where id = 9 and name='华为荣耀',
  18. p = Product.objects.filter(name='华为荣耀',id=9)
  19. #------ or 查询 -----------
  20. #SQL: select * from index_product where id = 9 or name='华为荣耀',
  21. from django.db.models import Q
  22. p = Product.objects.filter(Q(name='华为荣耀')|Q(id=9))
  23. # ------ count() ---------
  24. #SQL:使用count方法统计查询数据的数据量
  25. p = Product.objects.filter(name='荣耀V10').count
  26. p
  27. #------ distinct ------
  28. # SQL: select distinct name from index_product where name ='荣耀V10'
  29. p = Product.objects.values('name').filter(name='荣耀V10').distinct()
  30. p
  31. #------- order_by --------
  32. # SQL: select id, name from index_product order by id,
  33. p = Product.objects.order_by('-id','name')
  34. #------- group by -------
  35. select name, Sum(id) as 'id_sum' from index_product group by name order by null
  36. from django.db.models import Sum, Count
  37. p = Product.objects.values('name').annotate(Sum('id'))
  38. print(p.query)
  39. # ------ count() ---------
  40. # select Count(id) as 'id_count' from index_product
  41. p = Product.objects.aggregate(id_count=Count('id'))

image.png

多表查询

我们了解到数据表的读写操作,但仅仅局限在单个数据表的操作。在日常的开发中,常常需要对多个数据表同时进行数据查询。多个数据表查询需要数据表之间建立了表关系才得以实现。
一对多或一对一的表关系是通过外键实现关联的,而多表查询分为正向查询和反向查询。以模型Product和Type为例:
• 如果查询对象的主体是模型Type,要查询模型Type的数据,那么该查询称为正向查询。
• 如果查询对象的主体是模型Type,要通过模型Type查询模型Product的数据,那么该查询称为反向查询。
image.png
从上面的代码分析,因为正向查询的查询对象主体和查询的数据都来自于模型Type,因此正向查询在数据库中只执行了一次SQL查询。而反向查询通过t[0].product_set.values(‘name’)来获取模型Product的数据,因此反向查询执行了两次SQL查询,首先查询模型Type的数据,然后根据第一次查询的结果再查询与模型Product相互关联的数据。为了减少反向查询的查询次数,我们可以使用select_related方法实现,该方法只执行一次SQL查询就能达到反向查询的效果。select_related使用方法如下:
image.png

  1. p = Product.objects.select_related('type').values('name','type_type_name')
  2. print(p.query)

image.png

  1. p = Product.objects.select_related('type').all()
  2. print(p.query)

image.png

  1. p = Product.objects.select_related('type').filter(id_gt=8)
  2. print(p.query)

image.png

  1. p = Product.objects.select_related('type').filter(type_type_name='手机').all()
  2. p



参考文献:玩转Django 2.0/黄永祥著.-北京:清华大学出版社,2018