• Django下orm学习 一对多


    概念说明

    • ORM:关系对象映射的全称是 Object Relational Mapping, 简称ORM
    • SQLAlchemy: 是Python编程语言下的一款ORM框架,该框架建立在数据库API之上,使用关系对象映射进行数据库操作,简言之便是:将对象转换成SQL,然后使用数据API执行SQL并获取执行结果。

    ORM方法论基于三个核心原则:

    简单:以最基本的形式建模数据。
    传达性:数据库结构被任何人都能理解的语言文档化。
    精确性:基于数据模型创建正确标准化了的结构。

    django中遵循 Code Frist 的原则,即:根据代码中定义的类来自动生成数据库表。

    对于ORM框架里:

    我们写的类表示数据库的表
    如果根据这个类创建的对象是数据库表里的一行数据

    理解

    首先在理解ORM的时候,我们可以把一对多、多对多 分为正向和反向!

    什么是正向呢?看下面的代码!

    class UserType(models.Model):
        caption = models.CharField(max_length=32)
    
    
    class UserInfo(models.Model):
        user_type = models.ForeignKey(UserType)
        username = models.CharField(max_length=32)
        age = models.IntegerField()
    

    ForeignKey 在UserInfo表里,如果根据UserInfo去操作就是正向,

    因为 ForeignKey 不在UserType里,如果根据UserType去操作反向。

    下面我们分别说明 一对多、多对多。

    环境

    创建一个Project并且创建一个叫做api的APP,数据模型代码如上;

    安装一个插件 django-extensions ,这个插件可查看执行sql

    pip install django-extensions
    
    INSTALLED_APPS = (
        ...
        'api',
        'django_extensions',
        )
    

    生成数据库和表结构,这里我们用django默认的数据库sqlite3,如下是建表:

    python manage.py makemigrations api
    python manage.py migrate
    

    ORM一对多

    什么时候使用一对多?

    在设计表结构的时候什么时候使用一对多呢?比如我在创建用户的时候有个菜单让我们选择用户类型的时候,使用一对多!

    一对多正向反向

    首先怎们看下UserType这个表,他没有关联其他表我们在添加的时候没有什么特殊直接添加就行:

    进入django shell命令行

    python manage.py shell_plus --print-sql
    >>> from api.models import *
    

    我们依次添加:CEO、CFO、COO 3个用户组

    >>> UserType.objects.create(caption='CFO')
    BEGIN
    Execution time: 0.000000s [Database: default]
    INSERT INTO "api_usertype" ("caption") VALUES ('CFO')
    Execution time: 0.001000s [Database: default]
    <UserType: UserType object>
    
    idcaption
    1 CEO
    2 CFO
    3 COO

    正向:增

    在看下UserType这个表,默认他在创建的时候回有4列,ID、username、user_type_id、age

    | id | username | user_type_id | age |

    所以我们在创建UserType数据的时候有两种方法:第一种方法是直接根据这个字段进行添加数据!给user_type 加 '_id'

    >>> UserInfo.objects.create(username='one',age=18,user_type_id=1)
    INSERT INTO "api_userinfo" ("user_type_id", "username", "age") VALUES (1, 'one', 18)
    

    或者通过对象添加

    >>> usertype = UserType.objects.get(id=2)
    SELECT "api_usertype"."id", "api_usertype"."caption" FROM "api_usertype" WHERE "api_usertype"."id" = 2
    >>> UserInfo.objects.create(username='two',age=23,user_type=usertype)
    INSERT INTO "api_userinfo" ("user_type_id", "username", "age") VALUES (2, 'two', 23)
    

    添加数据后 userinfo表如下:

    idusernameageuser_type_id
    1 one 18 1
    2 two 23 2
    3 three 78 1

    正向:查

    • 查询所有用户type为CEO的用户名字
    >>> allceo = UserInfo.objects.filter(user_type__caption='CEO')
    >>> for i in allceo:
    ...     print i.username
    one
    three
    
    • 正向查询用户为one的所有身份,user_type
    >>> user = UserInfo.objects.filter(username='one')
    ...     print i.user_type.caption
    SELECT "api_usertype"."id", "api_usertype"."caption" FROM "api_usertype" WHERE "api_usertype"."id" = 1
    
    CEO
    

    反向:查

    我们知道 UserType 表与 UserInfo 表是通过 UserInfo 里面的 user_type_id 外键来建立联系的,做正向查询的时候通过 user_type_id 外这个外键就可以查询到 UserType 表里的数据。其实在这两个表创建联系的时候,Django在 UserType 表里
    也创建了一个隐藏的 userinfo 字段来与 UserInfo 表进行关联。那么如果我们要在 UserType 表里查看 one 所对应的所有 usertype 的话,就可以利用 UserType 表里的隐藏字段来关联用户名称。代码如下:

    • 反向查询用户为one的所有身份,user_type
    >>> user = UserType.objects.filter(userinfo__username='one')
    >>> for i in user:
    ...     print i.caption
    SELECT "api_usertype"."id", "api_usertype"."caption" FROM "api_usertype" INNER JOIN "api_userinfo" ON ("api_usertype"."id" = "api_userinfo"."user_type_id") WHERE "api_userinfo"."username" = 'one'
    
    CEO
    

    可以看到与上面正向查询的方式是不一样的;
    上面代码中的user还有如下几种方法:

    >>> for obj in user:
    ...     print obj.caption
    ...     print obj.id
    ...     print obj.userinfo_set  #理解为一种能力,可以获取所有当前这个用户类型的用户/或者这个用户类型的多个用户
    ...     print obj.userinfo_set.all()  #获取所有用户类型为COO的用户
    ...     print obj.userinfo_set.filter(username='one')  #获取用户类型为COO的并且用户为one的用户
    

    这里 userinfo_set 它相当于 UserInfo.objects.filter(user_type=obj)

    一对多的简单总结

    1、查询数据 也就是通过models.xxx.objects.filter()里填写查询条件的时候。这个时候获取的结果是一组数据行对象,不是具体的某个数据。跨表查询用到 对象名称__字段名(双下划线)
    2、获取数据 也是具体到要获取某个字段的数据的时候。跨表操作通过'.'来连接各个表
    3、反向查找的时候,查找的的表里会创建一个隐藏掉字段,这个字段名就是与创建外键的表同名
    4、反向获取数据的时候,通过xxx_set.all()才能获取到 xxx所有被匹配到的对象
    5、尽量用正向操作,反向的看着就麻烦。

    orm常用操作

    # 增
    models.Tb1.objects.create(c1='xx', c2='oo')  #增加一条数据,可以接受字典类型数据 **kwargs
    obj = models.Tb1(c1='xx', c2='oo')
    obj.save()
     #
    # 查
    models.Tb1.objects.get(id=123)         # 获取单条数据,不存在则报错(不建议)
    models.Tb1.objects.all()               # 获取全部
    models.Tb1.objects.filter(name='seven') # 获取指定条件的数据
    #
    # 删
    models.Tb1.objects.filter(name='seven').delete() # 删除指定条件的数据
    #
    改
    models.Tb1.objects.filter(name='seven').update(gender='0')  # 将指定条件的数据更新,均支持 **kwargs
    obj = models.Tb1.objects.get(id=1)    # 修改单条数据
    obj.c1 = '111'
    obj.save()                                                 
    
    #
    # 获取个数
    models.Tb1.objects.filter(name='seven').count()
    #
    # 大于,小于
    models.Tb1.objects.filter(id__gt=1)              # 获取id大于1的值
    models.Tb1.objects.filter(id__lt=10)             # 获取id小于10的值
    models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 获取id大于1 且 小于10的值
    #
    # in
    models.Tb1.objects.filter(id__in=[11, 22, 33])   # 获取id等于11、22、33的数据
    models.Tb1.objects.exclude(id__in=[11, 22, 33])  # not in
    #
    contains
    models.Tb1.objects.filter(name__contains="ven")
    models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
    models.Tb1.objects.exclude(name__icontains="ven")
    #
    # range
    models.Tb1.objects.filter(id__range=[1, 2])   # 范围bettwen and
    #
    # 其他类似
    startswith,istartswith, endswith, iendswith,
    #
    # order by
    models.Tb1.objects.filter(name='seven').order_by('id')    # asc
    models.Tb1.objects.filter(name='seven').order_by('-id')   # desc
    #
    # limit 、offset
    models.Tb1.objects.all()[10:20]
    #
    # group by
    from django.db.models import Count, Min, Max, Sum
    models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num'))
    SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"
    


    作者:撸大师
    链接:https://www.jianshu.com/p/b9c85da0b159
    來源:简书
    简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
  • 相关阅读:
    (数据科学学习手札33)基于Python的网络数据采集实战(1)
    (数据科学学习手札32)Python中re模块的详细介绍
    (数据科学学习手札31)基于Python的网络数据采集(初级篇)
    (数据科学学习手札30)朴素贝叶斯分类器的原理详解&Python与R实现
    (数据科学学习手札29)KNN分类的原理详解&Python与R实现
    (数据科学学习手册28)SQL server 2012中的查询语句汇总
    牛客3 F/G 牛牛的Link Power |线段树区间修改
    牛客2-H施魔法|线段树优化dp,维护区间最小值
    2020牛客寒假算法基础集训营1
    友情链接
  • 原文地址:https://www.cnblogs.com/floodwater/p/10037508.html
Copyright © 2020-2023  润新知