python django orm查询集总结

1 .什么是ORM (Object Relational Mapping )

它的作用是在关系型数据库和业务实体对象做一个映射,我们在操作具体业务对象的时候就可以省去了和SQL语句打交道,只需要简单的操作对象的属性和方法。

我们在model这个模块写的类名相当于数据库中的表名
根据这个类创建的对象相当于数据库表中的一个字段
字段名.id ,字段名2.name 表示这个字段对对应的数据

模型与模型之间的关系

1.多对一关系
一对多
举个列子一个知识对应多个流程,这里就是一对多的关系,通过相应的表来来建立一个联系,用ForeignKey来实现。在流程表引入知识对象。

class Knowledge(BaseModel):
    # 知识对象
    knowledge_name = models.CharField(u'知识名称', max_length=100)
    user_id = models.ForeignKey(User, null=True, on_delete=models.CASCADE)
class WorkFlow(BaseModel):
    # 知识流程审核
    process_status = models.CharField(u'流程状态', max_length=36)
    business_id = models.ForeignKey(Knowledge, on_delete=CASCADE)

通过知识表查process_status时结束的知识,
查询方式(表名称全小写__字段名称)

know=Knowledge.objects.filter(workflow__ process_status ='结束') #查询语句查询
process_status=know.workflow_set.filter(process_status ='结束') # 对象查询
补充:
know.workflow_set.all() #查询当前知识对象的所有流程状态对象
know.workflow_set.values('process_status') # 查询当前知识对象的所有流程状态和值(字典形式)

多对一
多个知识对应一个用户,通过相应的表来来建立一个联系,用ForeignKey来实现,知识表内存用户对象。

class Knowledge(BaseModel):
   # 知识对象
    knowledge_name = models.CharField(u'知识名称', max_length=100)
    user_id = models.ForeignKey(User, null=True, on_delete=models.CASCADE)
class User(AbstractUser):
	#用户
	name = models.CharField(max_length=90, blank=True, null=True, verbose_name='用户真实姓名'))

查name,查询方式(外键关联字段名称__字段名称)
Knowledge.objects.filter(user_id__name=‘毛毛’)
2.一对一
3.多对多

class Knowledge(BaseModel):
	    # 知识对象
	    knowledge_name = models.CharField(u'知识名称', max_length=100)
	    user_id = models.ForeignKey(User, null=True, on_delete=models.CASCADE)
class KnowledgeTag(BaseModel):
    # 知识标签
    tag_name = models.CharField(u'标签名称', max_length=200)
 
 class KnowledgeTagToKnowledge(BaseModel):
    # 知识对知识标签中间表
    tag_id = models.ForeignKey(KnowledgeTag, on_delete=CASCADE)
    knowledge_id = models.ForeignKey(Knowledge, on_delete=CASCADE)

查 tag_name,查询方式(表名称全小写__字段名称__字段名称)

查询语句:

knowledges = Knowledge.objects.filter(
                    workflow__process_status='结束',
                    knowledgeindexconfigure__organization_name=site_name,
                    user_id__name='毛毛',
                    knowledgetagtoknowledge__tag_id__ tag_name='毛毛',
                    **condition).order_by(
                    '-create_time')

总结:

  1. 在当前表内的外键,查询方式:外键关联字段名称__字段名称(查指示表用户姓名:user_id__name=‘毛毛’)
  2. 当前表的外键在其他表里,查询方式:表名称全小写__字段名称(查流程结束的知识:workflow__process_status=‘结束’)
  3. 两者可以混着用。即获取对象的方式,通过当前表查询,在当前表中的外键,可通过外键关联字段名称直接获取;当前表在其他表中作为外键关联,则需其他表名称全小写,即可获取其他表的对象。

一对多:
1.知识id在流程表中,外键关联,查状态是’‘结束’'的知识
表:

class Knowledge(BaseModel):
    # 知识对象
    knowledge_name = models.CharField(u'知识名称', max_length=100)
    user_id = models.ForeignKey(User, null=True, on_delete=models.CASCADE)
class WorkFlow(BaseModel):
    # 知识流程审核
    process_status = models.CharField(u'流程状态', max_length=36)
    business_id = models.ForeignKey(Knowledge, on_delete=CASCADE)

查询方式(外键关联查询:’‘表名称全小写__字段名称’’)

knowledges = Knowledge.objects.filter(
                    workflow__process_status='结束',
                  )

2.不同区域关联部分知识

class KnowledgeIndexConfigure(BaseModel):
    # 区域首页推荐文档配置
    knowledge_id = models.ForeignKey(Knowledge, on_delete=CASCADE)
    organization_name = models.CharField(u'专用站点名称', max_length=100, null=True, blank=True)

查询方式(外键关联查询:’‘表名称全小写__字段名称’’)
区域关联的文档:

knowledges = Knowledge.objects.filter(
                          knowledgeindexconfigure__organization_name=site_name
                       )

区域未关联的文档:

knowledges = Knowledge.objects.exclude(
                          knowledgeindexconfigure__organization_name=site_name
                       )

3.知识关联的用户姓名
表:

class Knowledge(BaseModel):
   # 知识对象
    knowledge_name = models.CharField(u'知识名称', max_length=100)
    user_id = models.ForeignKey(User, null=True, on_delete=models.CASCADE)
class User(AbstractUser):
	#用户
	name = models.CharField(max_length=90, blank=True, null=True, verbose_name='用户真实姓名'))

查询方式(外键关联字段名称__字段名称)

  Knowledge.objects.filter(user_id__name__icontains=keyword)

源自

 knowledges_keyword = Knowledge.objects.filter(Q(knowledge_number__icontains=keyword)
                                                          | Q(knowledge_name__icontains=keyword)
                                                          | Q(user_id__name__icontains=keyword),
                                                          workflow__process_status='结束')

4.查询用户创建的所有知识对象
查询方式(表名称全小写_set.all())
user为用户对象

 user. knowledge_set.all()
 #后可以直接用方法:user. knowledge_set.all().values('id')
 也可再次过滤:knowledges=user.knowledge_set.filter(article_type=0)
 			 if knowledges:
 			 	info=knowledges.values('id')[0].get('id')

或者反过来,查询知识的用户姓名:
know为知识对象

know.user_id.name

查询问题的所有原因对象

class DocumentProgrammer(BaseModel):
    # 文档问题对象
    issue_number = models.CharField(u'问题编号', max_length=200)  #格式为:iss-20190821001
    issue_name = models.CharField(u'问题名称', max_length=200)
class IssueCause(BaseModel):
    # 问题原因
    issue_id = models.ForeignKey(DocumentProgrammer, on_delete=CASCADE)

#issue为问题对象

issue.issuecause_set.all()

反过来查询,查原因对应的问题name:
cause为原因对象

cause.issue_id.issue_name

5.多条件查询

condition = {}
# 时间
line1 = ''
line2 = ''
if start_end != '':
    line1 = start_end.split('*')[0] + ' 00:00:00'
    line2 = start_end.split('*')[1] + ' 23:59:59'
if line1 or line2:
     # condition.update(
     #     {'workflow__process_end_time__gte': datetime.datetime.strptime(line1, '%Y/%m/%d %H:%M:%S')})
     # condition.update(
     #     {'workflow__process_end_time__lte': datetime.datetime.strptime(line2, '%Y/%m/%d %H:%M:%S')})
     condition.update({'create_time__gte': datetime.datetime.strptime(line1, '%Y/%m/%d %H:%M:%S')})
     condition.update({'create_time__lte': datetime.datetime.strptime(line2, '%Y/%m/%d %H:%M:%S')})

组织

organization_codes_list = organization_codes.split(',')
organization_ids = tuple(organization_codes_list)
if len(organization_ids) == 1:
    organization_ids = "'" + organization_ids[0] + "'"
sql = """select a.c_org_code from t_orgination a
        where a.C_STATUS='1' start with a.c_org_code in %s
        connect by prior a.c_org_code = a.c_org_parent_code""" % (organization_ids,)
knowledges_org = exe_sql_all(sql, db_name=RDKM_DB)
for k2 in knowledges_org:
    org_list.append(str(k2[0]))
if organization_id_list:
      condition.update({'organization_id__in': organization_id_list})

class Knowledge(BaseModel):
	    # 知识对象
	    knowledge_name = models.CharField(u'知识名称', max_length=100)
	    user_id = models.ForeignKey(User, null=True, on_delete=models.CASCADE)
class KnowledgeTag(BaseModel):
    # 知识标签
    tag_name = models.CharField(u'标签名称', max_length=200)
 
 class KnowledgeTagToKnowledge(BaseModel):
    # 知识对知识标签中间表
    tag_id = models.ForeignKey(KnowledgeTag, on_delete=CASCADE)
    knowledge_id = models.ForeignKey(Knowledge, on_delete=CASCADE)

查询方式(表名称全小写__字段名称__字段名称)

 Knowledge.objects.filter(knowledgetagtoknowledge__tag_id__tag_name=keyword)

查询

all_know = Knowledge.objects.filter(Q(knowledge_number__icontains=keyword)
                                                | Q(knowledge_name__icontains=keyword)
                                                | Q(user_id__name__icontains=keyword)
                                                | Q(knowledgetagtoknowledge__tag_id__tag_name=keyword),
                                                workflow__process_status='结束',
                                                **condition
                                                ).order_by('-create_time')

6.查询问题的原因的方案
表:

	class DocumentProgrammer(BaseModel):
   		 # 文档问题对象
	    issue_number = models.CharField(u'问题编号', max_length=200)  #格式为:iss-20190821001
    	issue_name = models.CharField(u'问题名称', max_length=200)
    	issue_desc = models.CharField(u'问题描述', max_length=500)
	class IssueCause(BaseModel):
	    # 问题原因
	    issue_id = models.ForeignKey(DocumentProgrammer, on_delete=CASCADE)
	    cause_number = models.CharField(u'原因编号', max_length=100)
  		cause_description = models.TextField(u'原因描述')
	class IssueSolution(BaseModel):
	    # 问题解决方案
	    solution_number = models.CharField(u'解决方案编号', unique=True, max_length=50)
	    solution_description = models.TextField(u'解决方案描述')
	    cause_id = models.ForeignKey(IssueCause, on_delete=CASCADE)

查询(表名称全小写__表名称全小写____字段名称)

DocumentProgrammer.objects.filter(issuecause__issuesolution__solution_description__contains=keyword)

源自

issues = DocumentProgrammer.objects.filter(Q(issue_number__contains=keyword)
                                           | Q(issue_name__contains=keyword)
                                           | Q(create_time__contains=keyword)
                                           | Q(user_id__name__contains=keyword)
                                           | Q(issue_desc__contains=keyword)
                                           | Q(issue_description__contains=keyword)
                                           | Q(issuecause__cause_description__contains=keyword)
                                           |Q(issuecause__issuesolution__solution_description__contains=keyword),
                                            Q(Q(issue_change=''),
                                             workflow__process_status='结束')
                                           ).order_by('create_time')

total = len(issuelist)
issues = Paginate(page=current_page, count=page_count).data( issues)

关系数据库本身没多多对多的关系,Django是在数据库中新建了一张表专门用来存储多对多的关系。
记得引用的ForeignKey和ManyToManyField一定要在Author的后面,如果不在后面要将参数写成字符串形式(‘Author’)。并且ForeignKey和ManyToManyField这段关系在两个类里面都可以声明,作用是一样的,django会自动为我们把另外一半关系给对称过去。

聚合查询

aggregate()是QuerySet 的一个终止子句,它返回一个包含一些键值对的字典。

键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。

from django.db.models import Avg, Sum, Max, Min, Count
Integral_source.objects.all().aggregate(Avg("a"))
#{'price__avg': 13.233333}
ret = Integral_source.objects.aggregate(Sum("a"))
#{'price__sum': Decimal('13.10')
ret =Integral_source.objects.aggregate(total_price=Sum("a"))
#{'total_price': Decimal('13.10')}
ret = Integral_source.objects.aggregate(avg_price=Avg("a"), max_price=Max("a"), min_price=Min("price"))
#{'avg_price': 4.366667, 'max_price': Decimal('12.00'), 'min_price': Decimal('0.10')}

分组查询

单表查询分组:
一、统计每个人的总积分

SELECT create_user_id, sum(a) as a
FROM g_Integral_source 
GROUP BY create_user_id order by a desc

orm查询:

users1 = Integral_source.objects.values('create_user_id').annotate(
    total=Sum('a')).order_by('-total').values('create_user_id','create_user_id__name','total')
result['data']=list(users1)

二、求按年度分组目标
sql:

select effective_time from t_objectives
        where user_id=%s 
         group by effective_time ORDER BY effective_time 

orm

Objectives.objects.filter(user_id=user_id).values('effective_time').annotate(
            count=Count('effective_time'))

连表查询的分组:按照部门分组求平均工资

select dept.name,AVG(salary) from employee inner join dept on (employee.dept_id=dept.id) group by dept_id;

ORM查询:

from django.db.models import Avg
Dept.objects.annotate(avg=Avg("employee__salary")).values("name", "avg")
​
Employee.objects.values("dept__name").annotate(avg=Avg("salary"))
#<QuerySet [{'dept__name': '垃圾部', 'avg': 221.0}, {'dept__name': '保安部', 'avg': 21.0}, {'dept__name': '教学部', 'avg': 999.0}]>                                                
​
Employee.objects.values("dept__name").annotate(avg=Avg("salary")).values('dept', "avg")
#<QuerySet [{'dept__name': '垃圾部', 'avg': 221.0}, {'dept__name': '保安部', 'avg': 21.0}, {'dept__name': '教学部', 'avg': 999.0}]>  
​
Employee.objects.values("dept__name")
#<QuerySet [{'dept__name': '垃圾部'}, {'dept__name': '保安部'}, {'dept__name': '教学部'}]>   

F查询

F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值。

商品表结构:

from django.db import models
​
class Product(models.Model):
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=6, decimal_places=2)
    # 库存数
    keep = models.IntegerField()
    # 卖出数
    sale = models.IntegerField()
​
    def __str__(self):
        return  "{}:{}:{}:{}".format(self.name, self.price, self.keep, self.sale)

示例:

from django.db.models import F
1.查询出卖出数大于库存数的商品
models.Product.objects.filter(sale__gt=F("keep"))
#<QuerySet [<Product: 跟哪吒学诗歌:59.00:50:10000>, <Product: 跟苑局学三不:55.00:100:200>]>
2.Django支持F()对象之间以及F()对象和常数之间的加减乘除和取模的操作
models.Product.objects.filter(sale__gt=F('keep')*2)
#<QuerySet [<Product: 跟哪吒学诗歌:59.00:50:10000>]>
3.修改操作也可以使用F函数:比如将每个产品的价格提高50元
models.Product.objects.all().update(price=F("price")+50)
4.把所有商品名后面加上"新款"
from django.db.models.functions import Concat
from django.db.models import Value
models.Product.objects.all().update(name=Concat(F("name"),  Value("新款")))

Q查询

filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 如果需要执行更复杂的查询(例如OR语句),可以使用Q对象

#卖出数大于100 并且 价格大于100块的
models.Product.objects.filter(sale__gt=100, price__gt=100)
#<QuerySet [<Product: 跟哪吒学诗歌新款:259.00:50:10000>, <Product: 跟苑局学三不新款:255.00:100:200>]>

示例:

from django.db.models import Q
1.查询卖出数大于100或者价格小于100的
models.Product.objects.filter(Q(sale__gt=100)|Q(price__lt=100))  #|:或
#<QuerySet [<Product: 跟哪吒学诗歌新款:259.00:50:10000>, <Product: 跟苑局学三不新款:255.00:100:200>]>
2.查询库存数是100并且卖出数不是0的产品
models.Product.objects.filter(Q(keep=100)&~Q(sale=0))           #&:与,~:非
models.Product.objects.filter(Q(kucun=100),~Q(maichu=0))
#<QuerySet [<Product: 跟苑局学三不新款:255.00:100:200>]>
models.Product.objects.filter(Q(kucun=100)&~Q(maichu=0)).values('name')
#<QuerySet [{'name': '跟苑局学三不新款'}]>
models.Product.objects.filter(Q(kucun=100)&~Q(maichu=0)).values_list('name')
#<QuerySet [('跟苑局学三不新款',)]>

查询函数可以混合使用Q 对象和关键字参数。所有提供给查询函数的参数(关键字参数或Q 对象)都将"AND”在一起。但是,如果出现Q 对象,它必须位于所有关键字参数的前面

#查询产品名包含新款, 并且库存数大于60或者价格小于100的产品

models.Product.objects.filter(Q(keep__gt=60)|Q(price__lt=100), name__contains="新款")
#<QuerySet [<Product: 跟苑局学三不新款:255.00:100:200>]>

12.3215 事务

开启一个事务可以包含一些sql语句,这些sql语句要么同时成功,要么都不成功,称之为事务的原子性 作用:事务用于将某些操作的多个SQL作为原子性操作,一旦有某一个出现错误,即可回滚到原来的状态,从而保证数据库数据完整性。

import os
if __name__ == '__main__':
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings")
    import django
    django.setup()

import datetime
from app01 import models

try:
    from django.db import transaction
    with transaction.atomic():                                #开启事务
        new_publisher = models.Publisher.objects.create(name="火星出版社")
        models.Book.objects.create(title="橘子物语", publish_date=datetime.date.today(), publisher_id=10)  
       # 指定一个不存在的出版社id,上一行创建一条出版社数据被回滚,数据库并未创建新数据
except Exception as e:
    print(str(e))     

12.3216 Django ORM执行原生SQL

很多情况下我们不需要将查询结果映射成模型,或者我们需要执行DELETE、 INSERT以及UPDATE操作,在这些情况下,我们可以直接访问数据库,完全避开模型层。我们可以直接从django提供的接口中获取数据库连接,然后像使用pymysql模块一样操作数据库

from django.db import connection, connections
cursor = connection.cursor()  # cursor = connections['default'].cursor()
cursor.execute("""SELECT * from auth_user where id = %s""", [1])
ret = cursor.fetchone()
ORM 中的CRUD操作
Create:

方法一:

task = {'a':'b'}
Task.object.create(**task)

这种方法的好处是可以直接把字典存到数据库里面
方法二:

task = Task(title='明天吃饭吗')
task.save()
Retrieve(检索)
res = Task.objects.all()
res = Task.objects.filter(id=0)  #对数据进行过滤,可以查询某一段数据
for row in res:
	print(row.id,row.title)  #不要直接将取到的所有数据进行for遍历查找用到,比如用到filter过滤,否则数据大服务器会蹦掉

filter(查询条件)

res = Task.objects.filter(id__gt=2)  #查询id大于2
all_knowledges = Knowledge.objects.filter(id__in=knowledges_id_list).order_by(
                    '-create_time')   #id在某个id列表内

使用filter进行登录验证

user= UserInfo.objects.filter(username=v,userpwd=p).first()
if not user:
print('登录失败')
else:
print('登录成功')

含义		       										 后缀             
大于          										 __gt             
小于             				 					 __lt    
大于等于												 __gte    
小于等于												 __lte     
包含          										 __contains       
不区分大小写      									 __iexact="abc"   
包含abc且不区分大小写 								 __icontains="abc"
正则表达式        							 		 __regex="^abc"   
正则表达式不区分大小写  								 __iregex="^abc"
在列表内												 __in=['12','13']

一些方法

方法说明
all()查询出所有
filter(id=10)查询出(为空时返回空值,不报错)
get(id=10)查询(为空则报错)
exclude(id__in=[1,3,4])排除满足条件的
order_by(“price”)QuerySet类型:根据price字段对所有数据排序
values_list(‘id’,‘user_id__name’)获取指定列的结果(元组样式,字段可支持基于双下划线字段方法(联表查询))
values(‘id’, ‘title’)获取指定列的结果(字典样式,字段可支持基于双下划线字段方法(联表查询))
distinct()去重
count()统计结果集中数据的个数
first()结果集中的第一个对象
exists()布尔值:结果集中是否有数据
reverse()反转

filter实现or

from django.db.models import Q
Item.objects.filter(Q(creator=owner) | Q(moderated=False))

filter实现and

Item.objects.filter(creator=owner),moderated=False)

filter实现or的满足其一

issues = DocumentProgrammer.objects.filter(Q(~Q(issue_desc='')
                                                         | ~Q(issue_description='')
                                                         | ~Q(issuecause__cause_description='')
                                                         | ~Q(issuecause__issuesolution__solution_description='')),
                                                       Q(issue_change=''),
                                                       workflow__process_status='结束'
                                                       ).order_by('-create_time')

上面表示,查询出问题的描述、简介、原因的描述、方案的描述任一条件不为空的问题结果。

BooleanField类型
is_take = models.BooleanField(u’是否结束归档’, default=False)
is_take是BooleanField类型,默认为False,结束归档后为True,查询是否存在正在讨论的内容,则orm查询时,可直接is_take=False;sql查询时is_take=‘false’

ParaGraphComments.objects.filter(
                        knowledge_id=int(knowledge_id),
                        paragraph=r[0],
                        is_take=True
                        ):

外键查询后重复问题

orkm_id = (f.id for f in OKRM.objects.filter(Q(user_id=user_id)
                                                         | Q(okrmtouser__user_id=user_id)))
orkms = OKRM.objects.filter(id__in=orkm_id)

exclude(排除)

Person.objects.filter(name__contains="文").exclude(age__lt=18) # 找出名称包含'文', 且排除年龄小于18岁的人

查看执行的SQL语句

Task.objects.all().query

获取指定列的结果

获取指定列的结果(元组样式)# QuerySet类型:字段值的元祖的列表

Task.objects.values_list('id','title')
#<QuerySet [('测试123345', 204), ('测试全文检索', 194), ('测试匿名帖子', 142), ('测试返回', 203), ('测试发帖01', 31)]>

获取指定列的结果(字典样式)# QuerySet类型:字段及字段值的字典的列表

Task.objects.values('id', 'title')
#<QuerySet [{'post_name': '测试123345', 'id': 204}, {'post_name': '测试全文检索', 'id': 194}, {'post_name': '测试匿名帖子', 'id': 142}, {'post_name': '测试返回', 'id': 203}, {'post_name': '测试发帖01', 'id': 31}]>

查询时可以这么简写

result={}
result['data']=[]
notices = Notice.objects.filter(public=True).values('id', 'pic_mark', 'pic_front', 'title', 'content',
                                                                    'pic_url')
notices = list(notices)
result['data'] = sorted(notices, key=lambda i: i['pic_mark'], reverse=False)

计算时间

import time
start_time=time.time()
end_time=time.time()
print(end_time-start_time)

提示:values_list 和 values 返回的并不是真正的 列表 或 字典,也是 queryset,他们也是 lazy evaluation 的(惰性评估,通俗地说,就是用的时候才真正的去数据库查)

Update

#根据指定某个条件修改

task= Task.objects.get(id=2)
task.title = 'new content'
task.save()

根据过滤条件修改

Task.objects.filter(id__lt=5).update(title='hello')

全部修改

Task.objects.all().update(title='hello world')
Delete

指定删除

task = Task.objects.get(id=2)
task.delete()

批量删除

Task.objects.filter(id_lt=10).delete() 
本地启动

py文件前加上这些配置:

import os
if __name__ == '__main__':
    # 指定当前py脚本需要加载的Django项目配置信息
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "RDPlatform.settings")
    import django
    django.setup()          # 启动Django项目
    from graphsystem.models import Post

    posts=Post.objects.filter(post_name__icontains='测试')
    print(posts)
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值