暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

浅谈orm多对多查询

大碗岛星期天下午的梦 2019-11-20
742

费了这么大劲写篇文章,最后发现还不如花时间听听火车。

‘黑色的不是夜晚,是漫长的孤单,看脚下一片黑暗,望头顶星光璀璨



orm: 全称Object-Relation Mapping,作用是在django中将对数据库的操作都转化成对类属性和方法的操作。

首先,在models中定义三个类,既三个数据库表,User(用户表)、Role(角色表)、Premission(权限表)



接着,插入数据,分别是用户表,角色表,权限表。当我们创建一个用户的时候,要分配相应的角色和权限。



1、本文的目标就是查询用户luka所拥有的权限(权限=url),查询语句如下。主要是弄清楚object、filter、values分别是什么意思,怎么用。

>>> curr_user = models.User.objects.filter(user='luka').first()
>>> curr_premission = curr_user.role.filter().values('premission__title','premission__url')


2、通过调用models中的User类,我们发现返回的类型是django.db.models.base.ModelBase,这是因为model中的类都是ModelBase的子类,ModelBase是在django.db.models.base中定义的。因此,在modles中定义的类是ModelBase的子类,继承了ModelBase的方法,包括 'objects'等,在这不列举。

>>> obj = models.User
>>> print(obj,type(obj))
<class 'web.models.User'> <class 'django.db.models.base.ModelBase'>


3、前面说了User继承了一些父类,在调用父类的objects时,实际上返回的是一个models.manager.Manager对象objects。Manager类是我们通过模型类去操作数据库的工具,django给每个定义的模型默认添加一个名为objects的Manager类的对象。简单来说就是,必须通过objects来操作数据库。

>>> obj = models.User.objects
>>> print(type(obj))
web.User.objects <class 'django.db.models.manager.Manager'>


4、在objects后面,介绍一下get和filter方法,这两个放到一起讲是因为这两者使用方法是一样,使用情景不一样。get方法是从数据库取得一个匹配的结果,返回一个对象,有多个结果或者没有匹配结果都会报异常。

>>> get_obj = models.User.objects.get(user='luka')
>>> print(get_obj,type(get_obj))
monika <class 'web.models.User'>


5、filter返回一个QuerySet,以下看出有两个luka用户,QuerySet里面是User类的两个对象。

>>> filter_obj = models.User.objects.filter(user='luka')
>>> print(filter_obj)
<QuerySet [<User: luka>, <User: luka>]>
>>> print(type(filter_obj))
<class 'django.db.models.query.QuerySet'>
>>> for j in filter_obj:
print(j,type(j))
luka <class 'web.models.User'>
luka <class 'web.models.User'>


6、回到最开始的查询,filter后面加first,既获取结果的第一条,返回的是User的一个对象。

>>> curr_user = models.User.objects.filter(user='luka').first()



7、从上面可知curr_user是User的一个实例,因此可查看User类中的属性,分别有user、password、role,

>>> curr_premission = curr_user.role.filter().values('premission__title','premission__url')


8、User类中的role是一个多对多属性,关联Role类,因此在role后面加all获取全部luka关联Role结果或者filter过滤。最终,我们得到了一个QuerySet,前面说了QuerySet里面是对象,也就是我们获得了一个Role对象,对象名叫“老板”,也就是luka的角色是老板。

>>> curr_premission =curr_user.role


>>> print(curr_premission,type(curr_premission))
web.Role.None <class 'django.db.models.fields.related_descriptors.create_forward_many_to_many_manager.<locals>.ManyRelatedManager'>
>>> curr_premission =curr_user.role.filter()
>>> print(curr_premission,type(curr_premission))
<QuerySet [<Role: 老板>]> <class 'django.db.models.query.QuerySet'>


9、最后,我们来看一下values的用法。values返回一个QuerySet,跟filter不一样的是,values返回的QuerySet里面是字典,其键对应于模型对象的属性名

>>> user_obj = models.User.objects.values()
>>> print(user_obj)
<QuerySet [{'id': 1, 'user': 'luka', 'password': '123'}, {'id': 2, 'user': 'tommy', 'password': '123'}, {'id': 3, 'user': 'jimmy', 'password': '123'}, {'id': 4, 'user': 'luka', 'password': '789'}]>
>>> print(type(user_obj))
<class 'django.db.models.query.QuerySet'>
>>> for i in user_obj:
print(i,type(i))
{'id': 1, 'user': 'luka', 'password': '123'} <class 'dict'>
{'id': 2, 'user': 'tommy', 'password': '123'} <class 'dict'>
{'id': 3, 'user': 'jimmy', 'password': '123'} <class 'dict'>
{'id': 4, 'user': 'luka', 'password': '789'} <class 'dict'>
>>> user_obj = models.User.objects.values('id','password')
>>> print(user_obj)
<QuerySet [{'id': 1, 'password': '123'}, {'id': 2, 'password': '123'}, {'id': 3, 'password': '123'}, {'id': 4, 'password': '789'}]>
>>> user_obj = models.User.objects.values().filter(id=1)
>>> print(user_obj)
<QuerySet [{'id': 1, 'user': 'luka', 'password': '123'}]>
>>> print(type(user_obj))
<class 'django.db.models.query.QuerySet'>


10、回到序号1中的两个查询语句,从序号8中可知我们得到了一个Role的对象,因此可用values查询Role对象中的属性,分别有name、premission。因为premission是多对对属性,可通过两个下划线获取关联的类对象的属性。

>>> curr_premission = curr_user.role.filter().values('premission__title','premission__url')
print(curr_premission,type(curr_premission))
<QuerySet [{'premission__title': '客户列表', 'premission__url': '/customer/list/'}, {'premission__title': '添加客户', 'premission__url': '/customer/add/'}, {'premission__title': '修改客户', 'premission__url': '/customer/edit/(?P<cid>\\d+)/'}, {'premission__title': '批量导入', 'premission__url': '/customer/import/'}, {'premission__title': '下载模板', 'premission__url': '/customer/tpl/'}, {'premission__title': '删除客户', 'premission__url': '/customer/list/(?P<cid>\\d+)/'}]> <class 'django.db.models.query.QuerySet'>


11、将luka用户所属权限url放入列表。

>>> pre_list = [i['premission__url'] for i in curr_premission]
>>> print(pre_list)
['/customer/list/', '/customer/add/', '/customer/edit/(?P<cid>\\d+)/', '/customer/import/', '/customer/tpl/', '/customer/list/(?P<cid>\\d+)/']



文章转载自大碗岛星期天下午的梦,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论