Django-3.ORM

ORM

对象关系映射表(Object Relation Mapping),基于ORM Python类操作数据库的表。

Django的ORM只能在Django使用,这里ORM是Django中独有的ORM。

Django通过类操作数据库的表,一个类相当于一张表。一个实例相当于一条记录

实例

1
2
3
4
5
6
7
class Emp():
id=...
name=...
salary=...
age=...
emp=Emp()
emp.id
Django数据库配置

Django支持sqlite,mysql,oracle,postgresql数据库

Django默认使用sqlite数据库,默认自带sqlite数据库驱动,引擎名称

django.db.backends.sqlite3

如果使用mysql需要修改引擎名称

django.db.backends.mysql

在python2中使用MySQLdb,在python3中使用PyMySQL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#在django项目中默认使用sqlite数据库,在setting里面有如下配置:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
#sqlite 小,简单.

#如果django连mysql就在setting配置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', #mysql驱动程序
'NAME': 'info', #数据库名称,需要事先创建好数据库create database info
'USER': 'root',
'PASSWORD': '1991',
'HOST': 'localhost',
'PORT': '3306',
}
}
Django创建表

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#1.创建app下的models.py文件
#more app/models.py
from django.db import models

#使用SQL语句创建表
#CREATE TABLE Book(id not null primary key auto_incremenet,book_name varchar(20),price float)

#使用ORM创建表
class Book(models.Model):
#如果不加models.Model,django不能区分是类还是表
book_name = models.CharField(max_length=20);
#相当于varchar(20)
price = models.FloatField();
#相当于float

#2.创建完了后执行
python manage.py makemigrations
#生成数据库脚本

#如果没有安装MySQL-python模块会提示找不到,django默认引擎是python2的MySQLdb,所有需要在项目下的__init__中添加
import pymysql
pymysql.install_as_MySQLdb()
#让pymysql代替MySQLdb

python manage.py migrate
#执行生成脚本

#3.如果后期添加表,都需要执行
python manage.py makemigrations
python manage.py migrate

#4.如果需要增加字段,直接在class里面写字段,执行makemigrations时会提示是否新增默认字段

ORM优点:

如果项目后期更换数据库时,直接改下驱动,而不需要修改SQL语句

如果是源生SQL语句,后期更换数据库还需要转换语法等信息

但是源生SQL语句效率比ORM高,ORM需要转化源生SQL

原生SQL使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
pip install PyMySQL

#导入模块,连接数据库
import pymysql
db=pymysql.connect('localhost','user','passwd','dbname')

#cursor()方法创建一个游标对象cursor
cursor = db.cursor()

#游标对象执行`select version()`
cursor.execute('select version()')

#游标对象使用fetchone()方法获取单条数据
data = cursor.fetchone()
print(data)

关闭mysql连接
db.close()
Django数据库操作日志
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
方法1:
直接修改mysql的配置文件my.cnf
more my.cnf
general_log = 1
重启后
mysql>show variables like '%general_log%'
查看general_log日志路径
每次执行SQL语句,就在general_log中产生日志


方法2:
在django项目中的setting.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',
},
}
}

ORM操作

表记录添加数据,一个类对应一张表,如何对表进行修改呢?通过实例化来修改,实例化一个对象就是一条记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Book(models.Model):
book_name = models.CharField(max_length=20);
price = models.FloatField();
这里的类就是Book,也是一张表

方法有两种
#在视图函数中先要导入models位置
from app_name.model import *

#方法1
def addbook(request):
b = Book('linux入门',59)
#这里就是创建了一条记录,注意这里只是创建了,并没有记录到数据库中
b.save()
#.save()方法才是保存到数据库中,

#方法2
def addbook(request):
Book.objects.create(book_name='linux入门',price=59)
#Book对象创建表,这里不需要save了
1
2
3
def delbook(request):
Book.objects.filter(book_name='linux入门').delete()
#先filter过滤后,在删除
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
比如修改某本书价格

#方法1
def changebook(request):
b = Book.objects.get(book_name='linux入门')
b.price=50
b.save()
#先get数据,然后在修改,在保存

#方法2
def changebook(request):
Book.objects.filter(book_name='linux入门').update(price=50)
#先filter,在update

#需要注意
#第二种方法filter修改不能用get。
#update是QuerySet对象的方法,get返回是一个model对象,并没有update方法,只能重新赋值
#filter返回的是QuerySet对象(filter里面条件可以有多个条件)
#filter是一个对象,而get是一个记录(记录不可迭代)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
filter(**kwargs)
#包含所有筛选条件匹配对象

all()
#查询所有结果
all()[:3]
#显示三条数据,相当于SQL中的limit

get(**kwargs)
#返回与所筛选条件相匹配的对象,返回结果只有一个,如果符合筛选条件对象不存在或者超出一个则抛出异常

#示例
1.假设在project_tab表查询project_lang='java',并且project_type='backend'的project_name
方法1
project_tab.objects.filter(project_lang='java').filter(project_type='backend').value('project_name')
方法2
project_dict={project_lang:'java',project_type:'backend'}
project_tab.objects.filter(**project_dict).value('project_name')

2.假设查询所有数据前三条
project_tab.objects.all()[:3]

3.假设查询所有数据后三条
project_tab.objects.all().order_by("-id")[:3]
#按id倒叙排序,获取三条
查询结果过滤
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
values(*field)
#返回一个valueQuerySet,一个特殊的QuerySet,运行后得到的并不是一系列的model示例对象,而是一个可迭代字典序列

exclude(**kwargs)
#包含所筛选条件不匹配的对象

order_by(*field)
#对查询结果排序

resverse()
#对查询结果反向排序

distinct()
#剔除重复记录

values_list(*field)
#类似values(),返回是一个元素序列,values返回的是字典序列

count()
#返回数据库中匹配查询(QuerySet)对象数量

first()
#返回第一条记录

last()
#返回最后挑一记录

exists()
#如果QuerySet包含数据,返回True,否则返回False
示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
book_list = Book.objects.all()
#相当于select * from Book

book_list = Book.object.all()[:1]
#相当于select * from Book limit 1

book_list = Book.objects.all()[::-1]
#倒序号

book_list = Book.objects.all()[::2]
#步长,类似list查找步长

book_list = Book.objects.first()
#获取第一个实例对象,跟get类似,不可迭代,在template中不能for循环
#first(),get(),last()这些获取都是实例对象,并非QuerySet集合对象

book_list = Book.objects.all().values('book_name','price')
#相当于select name,price from Book

book_list = Book.objects.all().values_list('book_name','price')
#同上,只不过这里返回是元祖形式,没有键值对

book_list = Book.objects.filter(price=20).values('book_name')
#相当于select name from Book where price=20

book_list = Book.objects.exclude(book_name='linux入门')
#相当于select * from Book where book_name != 'linux入门'

book_list = Book.objects.filter(book_name='linux入门').distinct()
#相当于select distinct name from Book

book_list = Book.objects.all().values(book_name='linux入门').distinct()
#同上

book_list = Book.objects.filter(book_name='linux入门').count()
#相当于select count(book_name) from Book where book_name='linux入门'
模糊查询
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
book_list = Book.objects.filter(price__gt=150).value("book_name","price");
#相当于select book_name,price from Book where price > 150

book_list = Book.objects.filter(name__icontains="linux").value("book_name","price")
#相当于select book_name price from Book where book_name like %linux%

book_list = Book.objects.filter(price__lt=200,price__gt=150).value("book_name","price")
#相当于select book_name,price from Book where price > 150 and price < 200

filter(id__lt=10,id__gt=1); id大于1,小于10
filter(id__in=[10,20,30]); id在10,20,30
filter(id__range=[1,10]); id范围在1~10之间
filter(name__contains="ven"); like %ven%
filter(name__icontains="ven"); like %ven%对大小写不敏感
exclude(id_in=[10,20,30]); id不包含10,20,30

ORM多表操作

表与表的之间的关系

一对多,一个表与另外一个表关联,另一个表可以对应这个表的多条记录

多对多,需要三张表,其中一个表记录 表A 和 表B 的两个关系。

一对一,通常用作详细页,自关联

一对多

ForeignKey

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
class Book(models.Model):
name=models.CharField(max_length=30)
price=models.IntegerField()
pub_date=models.DateField()
publish=models.ForeignKey("Publish")

#这里是个关联Publish记录,一旦实例出来就是一对象,通过该值就可找到Publish记录,反之Publish可以通过该值反向查找到Book
#book子表外键publish对应主表Publish,不需要指定具体对应主表那个键,会自动创建
#子表外键publish创建时会自动创建publish_id
#如果这里是publish_id那么创建的时候就是publish_id_id
#如果Publish不加引号,需要把class Publish(models.Model)放在Class Book里面

class Publish(models.Model):
name=models.CharField(max_length=32)
address=models.CharField(max_length=32)

class author(models.Model):
name=models.CharField(max_length=25)


多表添加
方式1
Book.objects.create(name='linux',price=200,pub_date="2019-01-04",publish_id=2);
#这里前提是Publish里面已经存在了id=2的记录

#方式2
pub = Publish.objects.filter(name='人民出版')[0]
Book.objects.create(name='linux',price=55,pub_date="2019-01-04",publish=pub);
#将人民出版的id,赋值给publish,不需要写publish_id


多表查询
1.正向查询
#方式1
通过书名查询出版社
book = Book.objects.get(name='python');
print(book.publish_id)
print(book.publish)
print(book.pubish.address,book,publish.name)

#方式2
通过出版社查询书的名称和价格
pub = Publish.objects.filter('name'='人民出版')[0]
book = Book.objects.filter(publish=pub).values('name','price');
#需要注意,如果这里是publish_id就不能获取了

2.方向查询
#方式1
pub=Publish.objects.filter(name='人民出版')[0]
print(pub.book_set.all())
看完了?赏个鸡腿钱,谢谢老板!