wenblogs

Python下ORM介绍及常见操作

对象关系映射(英语:Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序设计技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。

ORM操作(对象关系映射)

    Http请求:

        url -> 视图(模板+数据)

    ORM利用pymysql第三方工具连接数据库

        默认:

            SQLlite

        MySQL:

            mysql -> MySQLDB(修改django默认连接mySQL方式)

步骤:

    1. 创建数据库 orm

    2. 在主目录下的settings.py修改DATABASES项

DATABASES = {
    'default': {
    'ENGINE': 'django.db.backends.mysql',
    'NAME': '',
    'USER': 'root',
    'PASSWORD': '',
    'HOST': 'localhost',
    'PORT': 3306,
    }
  }

    3. 在主目录下的__init__.py增加代码

import pymysql
pymysql.install_as_MySQLdb()

 

ORM操作数据

首先在models中新建两张表做为示例,如下

from django.db import models
# 新建部门和用户信息两张表,其中各自表的id会自动生成
# UserInfo表中的dp_id外键关联Department表
class Department(models.Model):
    title = models.CharField(max_length=32)

class UserInfo(models.Model):
    username = models.CharField(max_length=32)
    age = models.IntegerField(,max_length=32)
    dp_id = models.ForeignKey(to='Department')

 

增删改查

from app01 import models
#新增
# models.Department.objects.create(title='财务部')
# models.Department.objects.create(title='人事部')
# models.UserInfo.objects.create(username='曹操',age=18,dp_id=3)
#删除
# models.Department.objects.filter(id=1).delete()
#查询
# alist = models.Department.objects.all()
# alist = models.Department.objects.filter(id__gt=2)  // 大于2
# alist = models.Department.objects.filter(id__lt=2)  // 小于2 更多查用查询条件见下方
# for i in alist:       //所有查询都是如此输出
#     print(i.id,i.title)
#更新
models.UserInfo.objects.filter(nid='1').update(username="曹操曹")

ORM常用查询

__gt     大于
__lt     小于
__gte    大于等于
__lte    小于等于
__in[ ,] 存在于一个list范围内
__startwith      以…开头
__istartwith     以…开头(忽略大小写)
__endwith        以…开头
__iendwith       以…开头(忽略大小写)
__exact         精确等于like"aaa"
__iexact        精确等于 忽略大小写 like"aaa"
__contains      包含(区分大小写)
__icontains     包含(不区分大小写)
__range         在…范围内
__exclude       除…之外
View Code

 

外键获取数据(跨表)

 通过外键字段跨表操作obj.dp.title,如果ug表有外键关联其他表,还可加 . 继续获取

 下面代码输出 每个用户的姓名和对应的部门id、部门名

# UserInfo,dp是FK字段 - 正向操作
obj = models.UserInfo.objects.all()
for obj in alist:
    print(obj.username,obj.age,obj.dp_id,obj.dp.title)

注意:反向操作中的obj.userinfo_set.all()或者obj.userinfo_set.filter()得到的是Queryset类型数据,需要循环从而输出想要的结果

#Department,表名小写_set.all() - 反向操作
obj = models.Department.objects.all().first()
print(obj.id,obj.title)
for row in obj.userinfo_set.all():  //或obj.userinfo_set.filter(条件)
    print(row.username,row.age)

 

values和values_list

 

被关联表的跨表反向操作

  示例为values,实则values_list也可以用同样的方法实现

  如果加的是主表的小写,输出则为主表的id,指定字段用双下划线

  v = models.Department.objects.values('id','title','userinfo','小写的表名/小写的表名__主表字段')

v = models.Department.objects.values('id','title','userinfo')
# < QuerySet[
#       {'id': 2, 'title': '财务部', 'userinfo': 2},
#       {'id': 3, 'title': '人事部', 'userinfo': 1},
#       {'id': 4, 'title': '技术部', 'userinfo': None},
#       {'id': 5, 'title': 'xx部', 'userinfo': None}] >
v1 = models.Department.objects.values('id','title','userinfo__username')
# < QuerySet[
#       {'id': 3, 'title': '人事部', 'userinfo__username': '曹操曹'},
#       {'id': 2, 'title': '财务部', 'userinfo__username': 'hh0'},
#       {'id': 4, 'title': '技术部', 'userinfo__username': None},
#       {'id': 5, 'title': 'xx部', 'userinfo__username': None}] >

PS:前面的所有数据都会显示,如果没有对应的数据,默认显示None

 

排序与分组

排序orderby

v = models.UserInfo.objects.all().orderby('-id','name')

  PS: ‘-’为倒序,也可多条件排序

 

分组annotate

from django.db.models import Count,Sum,Max,Min
v = models.UserInfo.objects.values('username').annotate(xx=Count('nid'))
print(v.query)
#SELECT `nid`, `username`, `password`, `age`,`ug_id`, 
#COUNT(`app01_userinfo`.`nid`) AS`xx` 
#FROM userinfo GROUPBY `nid`

  PS:分组前后还可进行filter筛选

 

F和Q

F,更新时用于获取原来的值

from django.db.models import F,Q
models.UserInfo.objects.all().update(age=F("age")+1)

 

Q,用于构造复杂查询条件

# 应用一:
models.UserInfo.objects.filter(Q(id__gt=1))
models.UserInfo.objects.filter(Q(id=8) | Q(id=2))
models.UserInfo.objects.filter(Q(id=8) & Q(id=2))
# 应用二:
q1 = Q()
q1.connector = 'OR'
q1.children.append(('id__gt', 1))
q1.children.append(('id', 10))
q1.children.append(('id', 9))


q2 = Q()
q2.connector = 'OR'
q2.children.append(('c1', 1))
q2.children.append(('c1', 10))
q2.children.append(('c1', 9))

q3 = Q()
q3.connector = 'AND'
q3.children.append(('id', 1))
q3.children.append(('id', 2))
q2.add(q3,'OR')
   
con = Q()
con.add(q1, 'AND')
con.add(q2, 'AND')
 #相当于(id=1 or id=10 or id=9 or(id=1 and id=2)) and (c1=1 or c1=10 or c1=9)
models.UserInfo.objects.filter(con)

 

extra

extra, 额外查询条件以及相关表,排序

models.UserInfo.objects.filter(id__gt=1)
models.UserInfo.objects.all() 
# id name age ut_id
      
models.UserInfo.objects.extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
# a. 映射
    # select 
    # select_params=None
    # select 此处 from 表

# b. 条件
    # where=None
    # params=None,
    # select * from 表 where 此处

# c. 表
    # tables
    # select * from 表,此处

# d. 排序
    # order_by=None
    # select * from 表 order by 此处


models.UserInfo.objects.extra(
    select={'newid':'select count(1) from app01_usertype where id>%s'},
    select_params=[1,],
    where = ['age>%s'],
    params=[18,],
    order_by=['-age'],
    tables=['app01_usertype']
)
"""
select 
app01_userinfo.id,
    (select count(1) from app01_usertype where id>1) as newid
    from app01_userinfo,app01_usertype
where 
    app01_userinfo.age > 18
order by 
    app01_userinfo.age desc
""" 
result = models.UserInfo.objects.filter(id__gt=1).extra(
    where=['app01_userinfo.id < %s'],
    params=[100,],
    tables=['app01_usertype'],
    order_by=['-app01_userinfo.id'],
    select={'uid':1,'sw':"select count(1) from app01_userinfo"}
)
print(result.query)
# SELECT (1) AS "uid", (select count(1) from app01_userinfo) AS "sw",
"app01_userinfo"."id", "app01_userinfo"."name", "app01_userinfo"."age", "app01_userinfo"."ut_id" 
FROM "app01_userinfo" , "app01_usertype" 
WHERE ("app01_userinfo"."id" > 1 
AND (app01_userinfo.id < 100)) ORDER BY ("app01_userinfo".id) DESC

 

原生SQL语句

from django.db import connection, connections
        
cursor = connection.cursor() # connection=default数据
cursor = connections['db2'].cursor()

cursor.execute("""SELECT * from auth_user where id = %s""", [1])

row = cursor.fetchone()
row = cursor.fetchall()

 

result

result = models.UserInfo.objects.raw('select * from userinfo')
[obj(UserInfo),obj,]
result = models.UserInfo.objects.raw('select id,1 as name,2 as age,4 as ut_id from usertype')
[obj(UserInfo),obj,]

v1 = models.UserInfo.objects.raw('SELECT id,title FROM app01_usertype',translations=name_map)

 

 

ORM多对多操作 

  1. 自定义类方法创建关系表

  2. django自带ManyToManyFiled(),此方法只生成3个字段-自表id和另外两表id

  3. 两种混合使用

        - 但是此处的manytomany只可使用查询和清空,类方法不受影响

            obj.m.all()

            obj.m.clear()

自定义第三张表

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

class Class(models.Model):
    title = models.CharField(max_length=32)

class Mas(models.Model):
    n = models.ForeignKey('Teacher', on_delete=models.CASCADE)
    t = models.ForeignKey('Class', on_delete=models.CASCADE)



# 1
obj = models.Teacher.objects.filter(name='丁冰冰').first()
mas_list = obj.mas_set.all()for row in mas_list:
print(row.t.title)

# 2
mas_list = models.Mas.objects.filter(n__name='丁冰冰')
for row in mas_list:
print(row.t.title)

# 3
mas_list = models.Mas.objects.filter(n__name='丁冰冰').values('t__title')
for row in mas_list:
print(row['t__title'])

# 4
mas_list = models.Mas.objects.filter(n__name='丁冰冰').select_related('t')
for obj in mas_list:
print(obj.t.title)

 

使用ManyToManyFiled创建第三张表

class Teacher(models.Model):
    name = models.CharField(max_length=32)
    m = models.ManyToManyField('Class')

class Class(models.Model):
    title = models.CharField(max_length=32)



obj = models.Teacher.objects.filter(name='丁冰冰').first()
# 增删add、remove可用单数、多数、列表
obj.m.add(4)
obj.m.add(1,3)
obj.m.add(*[2,])
#remove同add操作

obj.m.set([1,3,])  # set为重置

Q = obj.m.all()
#[Q为Class的对象]
print(Q)
cla_list = obj.m.all()
cla_list = obj.m.filter(title='5班')

obj.m.clear()  # 清除所有有关’丁冰冰‘的关系

# 反向获取数据同 一对多(小写表名_set)
obj = models.Class.objects.filter(title='5班').first()
v = obj.teacher_set.all()

posted on 2021-02-25 20:15  wenblogs  阅读(562)  评论(0编辑  收藏  举报

导航