• Django 之ORM操作


    1、什么是ORM?

      全称关系对象映射Object Relational Mapping(简称ORM),是通过描述面向对象与数据库之间的对应的元数据,将对象持久化的更新到数据库中。

      有了ORM,就不需要自己去手写SQL语句,ORM会根据编写的面向对象代码自动翻译成SQL语句,提高开发效率,但是处理数据的能力不是最优的。

    2、映射关系

      

    3、在Django项目中,使用ORM前的一些配置操作

      1、手动创建一个数据库

      2、在Django项目中的settings.py文件中,找到这个字段,改成如下格式

    DATABASES = {
        "default": {
            "ENGINE": "django.db.backends.mysql",
            "NAME": "你的数据库名称",  # 需要自己手动创建数据库
            "USER": "数据库用户名",
            "PASSWORD": "数据库密码",
            "HOST": "数据库IP",
            "POST": 3306
        }
    }

      3、在settings.py同级目录中的__init__.py文件中,导入pymysql

    import pymysql
    pymysql.install_as_MySQLdb()

      4、在Django项目下的app包下的models文件中,创建类,这个类就是要与数据库进行对应的那个映射关系。

    from django.db import models    #导入models模块
    
    
    class Class(models.Model):       #继承models.Model
        id = models.AutoField(primary_key=True)
        Class_name = models.CharField(max_length=32)

      5、在models中有变更,需要执行两条命令来保证数据库与对象之间的对应

        ·1

    python manage.py  makemigrations
    #    记录models的变更

        ·2

    python manage.py migrate
    #    将models中的代码翻译成SQL语句,同步到数据库中

    4、常用字段

      AutoField:

        自增长字段,必填参数为(primary_key=True)设置成主键。不写的时候,Django会自动创建。一个类中不能出现两个AutoField字段。

      CharField:

        字符串类型,必须提供max_length参数,表示字符串的最大长度。

      IntegerField:

        整数类型,数值范围-2147483646~2147483646

      DataField

        日期类型,日期格式为YYYY-MM-DD

        参数:

          ·auto_now:每次修改时修改为当前的时间

          ·auto_now_add:新创建对象时自动添加当前时间

        auto_now 和 auto_now_add 和 default参数是互斥的,不能够同时设置。

      DatatimeField

        日期类型,与DataField不同的是,增加了时分秒。

        格式为YYYY-MM-DD HH:MM:ss

    5、自定义字段

      我们可以自己去定义字段来使用,例如自定义一个char类型字段

    class MyCharField(models.Field):
        """
        自定义的char类型的字段类
        """
        def __init__(self, max_length, *args, **kwargs):
            self.max_length = max_length
            super(MyCharField, self).__init__(max_length=max_length, *args, **kwargs)
     
        def db_type(self, connection):
            """
            限定生成数据库表的字段类型为char,长度为max_length指定的值
            """
            return 'char(%s)' % self.max_length

      使用自定义字段

    class Class(models.Model):
        id = models.AutoField(primary_key=True)
        title = models.CharField(max_length=25)
        # 使用自定义的char类型的字段
        cname = MyCharField(max_length=25)

    6、字段参数

      我们在定义某个字段的时候,可以有多个参数,比如null=True表示允许该字段可以为空,等等,下面就是一些字段的参数

       null                数据库中字段是否可以为空
        db_column           数据库中字段的列名
        default             数据库中字段的默认值
        primary_key         数据库中字段是否为主键
        db_index            数据库中字段是否可以建立索引
        unique              数据库中字段是否可以建立唯一索引
        unique_for_date     数据库中字段【日期】部分是否可以建立唯一索引
        unique_for_month    数据库中字段【月】部分是否可以建立唯一索引
        unique_for_year     数据库中字段【年】部分是否可以建立唯一索引
     
        verbose_name        Admin中显示的字段名称
        blank               Admin中是否允许用户输入为空
        editable            Admin中是否可以编辑
        help_text           Admin中该字段的提示信息
        choices             Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
                            如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)
     
        error_messages      自定义错误信息(字典类型),从而定制想要显示的错误信息;
                            字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date
                            如:{'null': "不能为空.", 'invalid': '格式错误'}
     
        validators          自定义错误验证(列表类型),从而定制想要的验证规则
                            from django.core.validators import RegexValidator
                            from django.core.validators import EmailValidator,URLValidator,DecimalValidator,
                            MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator
                            如:
                                test = models.CharField(
                                    max_length=32,
                                    error_messages={
                                        'c1': '优先错信息1',
                                        'c2': '优先错信息2',
                                        'c3': '优先错信息3',
                                    },
                                    validators=[
                                        RegexValidator(regex='root_d+', message='错误了', code='c1'),
                                        RegexValidator(regex='root_112233d+', message='又错误了', code='c2'),
                                        EmailValidator(message='又错误了', code='c3'), ]
                                )
    字段参数

    7、多表关系和参数

    ForeignKey(ForeignObject) # ForeignObject(RelatedField)
        to,                 # 要进行关联的表名
        to_field=None,      # 要关联的表中的字段名称
        on_delete=None,     # 当删除关联表中的数据时,当前表与其关联的行的行为
                            - models.CASCADE,删除关联数据,与之关联也删除
                            - models.DO_NOTHING,删除关联数据,引发错误IntegrityError
                            - models.PROTECT,删除关联数据,引发错误ProtectedError
                            - models.SET_NULL,删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)
                            - models.SET_DEFAULT,删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)
                            - models.SET,删除关联数据,
                                   a. 与之关联的值设置为指定值,设置:models.SET(值)
                                   b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)
     
                                        def func():
                                            return 10
     
                                        class MyModel(models.Model):
                                            user = models.ForeignKey(
                                                to="User",
                                                to_field="id"
                                                on_delete=models.SET(func),)
        related_name=None,          # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()
        related_query_name=None,    # 反向操作时,使用的连接前缀,用于替换【表名】     如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
        limit_choices_to=None,      # 在Admin或ModelForm中显示关联数据时,提供的条件:
                                    # 如:
                            - limit_choices_to={'nid__gt': 5}
                            - limit_choices_to=lambda : {'nid__gt': 5}
     
                            from django.db.models import Q
                            - limit_choices_to=Q(nid__gt=10)
                            - limit_choices_to=Q(nid=8) | Q(nid__gt=10)
                            - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
        db_constraint=True          # 是否在数据库中创建外键约束
        parent_link=False           # 在Admin中是否显示关联数据
     
     
    OneToOneField(ForeignKey)
        to,                 # 要进行关联的表名
        to_field=None       # 要关联的表中的字段名称
        on_delete=None,     # 当删除关联表中的数据时,当前表与其关联的行的行为
     
                            ###### 对于一对一 ######
                            # 1. 一对一其实就是 一对多 + 唯一索引
                            # 2.当两个类之间有继承关系时,默认会创建一个一对一字段
                            # 如下会在A表中额外增加一个c_ptr_id列且唯一:
                                    class C(models.Model):
                                        nid = models.AutoField(primary_key=True)
                                        part = models.CharField(max_length=12)
     
                                    class A(C):
                                        id = models.AutoField(primary_key=True)
                                        code = models.CharField(max_length=1)
     
    ManyToManyField(RelatedField)
        to,                         # 要进行关联的表名
        related_name=None,          # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()
        related_query_name=None,    # 反向操作时,使用的连接前缀,用于替换【表名】     如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
        limit_choices_to=None,      # 在Admin或ModelForm中显示关联数据时,提供的条件:
                                    # 如:
                                        - limit_choices_to={'nid__gt': 5}
                                        - limit_choices_to=lambda : {'nid__gt': 5}
     
                                        from django.db.models import Q
                                        - limit_choices_to=Q(nid__gt=10)
                                        - limit_choices_to=Q(nid=8) | Q(nid__gt=10)
                                        - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
        symmetrical=None,           # 仅用于多对多自关联时,symmetrical用于指定内部是否创建反向操作的字段
                                    # 做如下操作时,不同的symmetrical会有不同的可选字段
                                        models.BB.objects.filter(...)
     
                                        # 可选字段有:code, id, m1
                                            class BB(models.Model):
     
                                            code = models.CharField(max_length=12)
                                            m1 = models.ManyToManyField('self',symmetrical=True)
     
                                        # 可选字段有: bb, code, id, m1
                                            class BB(models.Model):
     
                                            code = models.CharField(max_length=12)
                                            m1 = models.ManyToManyField('self',symmetrical=False)
     
        through=None,               # 自定义第三张表时,使用字段用于指定关系表
        through_fields=None,        # 自定义第三张表时,使用字段用于指定关系表中那些字段做多对多关系表
                                        from django.db import models
     
                                        class Person(models.Model):
                                            name = models.CharField(max_length=50)
     
                                        class Group(models.Model):
                                            name = models.CharField(max_length=128)
                                            members = models.ManyToManyField(
                                                Person,
                                                through='Membership',
                                                through_fields=('group', 'person'),
                                            )
     
                                        class Membership(models.Model):
                                            group = models.ForeignKey(Group, on_delete=models.CASCADE)
                                            person = models.ForeignKey(Person, on_delete=models.CASCADE)
                                            inviter = models.ForeignKey(
                                                Person,
                                                on_delete=models.CASCADE,
                                                related_name="membership_invites",
                                            )
                                            invite_reason = models.CharField(max_length=64)
        db_constraint=True,         # 是否在数据库中创建外键约束
        db_table=None,              # 默认创建第三张表时,数据库中表的名称
    多表关系和参数

    8、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.exclude(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()   # 修改单条数据

     9、13条方法

        1、返回对象列表,返回的是一个QuerySet对象  <QuerySet [ ]>

          all()          查询所有结果

          filter(筛选条件)           筛选

          exclude(条件)        查询除了该条件以外的其他对象

          order_by()        排序,默认是升序,oder_by(-'price')加负号为降序

          reverse()        降序

          distinct()         去重

          values()          返回一个ValueQuerySet------一个特殊的QuerSet,values返回的是一个字典,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典。

          values_list()         获取到的是对象的值,拿到的是一个元祖

        2、获取对象

          get()          获取到的是一个对象,并且有且只有一个

          first()          获取到第一个对象

          last()          获取到最后一个对象

        3、返回数字

          count()        计数,返回数据库中匹配查询的对向数量

        4、返回布尔值

          exists()           判断存不存在,如果QuerySet包含数据,就返回True,否则返回False

    10、单表查询的双下方法

        1、id__lt=10    id小于10的

        2、id__gt=10    id大于10的

        3、id__lte=10    id小于等于10

           id__gte=10    id大于等于10

        4、id__in=[···]    id在这个列表中的

        5、id__range=[1,3]  id范围在1到3的

        6、name__contains = 'wb'    获取name字段包含'wb'所有满足条件的字段

        7、name__startswith()       以·····开头    

          name__istartswith()       以·····开头,不区分大小写

        8、name__endswith()        以·····结尾

          name__iendswith()      以·····结尾,不区分大小写

        9、xx__year=2017        找到年份是2017年的

    11、ForeignKey操作

      一、

        1、对象查询

          语法:对象.关联字段.字段

        示例:

    book_obj = models.Book.objects.first()  # 第一本书对象
    print(book_obj.publisher)  # 得到这本书关联的出版社对象
    print(book_obj.publisher.name)  # 得到出版社对象的名称

        2、字段查询

          语法:

            关联字段__字段

        示例:

    print(models.Book.objects.values_list("publisher__name"))

      二、反向操作

      何为反向操作?

      如果A对B设了外键,那么从A查询B就属于正向查询,B查询A就是反向查询

        1、对象查找

        语法:

          obj.表明_set

        示例:

        

    publisher_obj = models.Publisher.objects.first()  # 找到第一个出版社对象
    books = publisher_obj.book_set.all()  # 找到第一个出版社出版的所有书
    titles = books.values_list("title")  # 找到第一个出版社出版的所有书的书名

        2、字段查找

        语法:

          表明_字段

        示例:  

    titles = models.Publisher.objects.values_list("book__title")

    12、ManyToManyField

        方法:

        1、create()

        创建一个新对象,保存对象,并将它添加到关联对象中,返回新创建的对象。

    >>> import datetime
    >>> models.Author.objects.first().book_set.create(title="番茄物语", publish_date=datetime.date.today())

        2、add()

        把制定的model对象添加到关联对象中。

        添加对象

    >>> author_objs = models.Author.objects.filter(id__lt=3)
    >>> models.Book.objects.first().authors.add(*author_objs)

        添加id

    >>> models.Book.objects.first().authors.add(*[1, 2])

        3、set()

        更新model对象的关联对象

    >>> book_obj = models.Book.objects.first()
    >>> book_obj.authors.set([2, 3])

        4、remove()

        从关联对象集中移除执行的model对象

    >>> book_obj = models.Book.objects.first()
    >>> book_obj.authors.remove(3)

        5、clear()

        从关联对象集中移除一切对象

    >>> book_obj = models.Book.objects.first()
    >>> book_obj.authors.clear()

        注意:对于ForeignKey对象,clear()和remove()方法仅在null=True时存在。

        如果ForeignKey字段不设置null=True时,就没有clear()和remove()方法。

        6、总结

          对于所有类型的关联字段,add()、create()、remove()和clear(),set()都会马上更新数据库。换句话说,在关联的任何一端,都不需要在调用save()方法。

    13、聚合查询

        1、aggregate()是QuerySet()的一个终止字句,意思是,它之后不能再有链式操作。返回的是一个包含一些键值对的字典。生成的字典的key是查询的字段和聚合函数的名称自动拼接组成的,也可以进行重新命名。

        2、可能用到的聚合函数:  

    from django.db.models import Avg, Sum, Max, Min, Count

        示例:

    >>> from django.db.models import Avg, Sum, Max, Min, Count
    >>> models.Book.objects.all().aggregate(Avg("price"))
    {'price__avg': 13.233333}          #得到的结果是个字典,key进行了自动拼接

        如果想要进行重命名,可以向聚合子句提供。

    >>> models.Book.objects.aggregate(average_price=Avg('price'))  #用average_price重新命名,这样就不会有自动生成的名字了
    {'average_price': 13.233333}   

        3、如果想要生成多个聚合,可以向aggregate()子句中添加多个参数。比如,如果你除了想知道书籍的平均值还想知道图书馆中价格最大和最小的书籍的价格,可以这样查询:

    >>> models.Book.objects.all().aggregate(Avg("price"), Max("price"), Min("price"))
    {'price__avg': 13.233333, 'price__max': Decimal('19.90'), 'price__min': Decimal('9.90')}

    14、分组

        1、分组就是将事务进行一个区分,归类。比如班级的学生,以性别分组,就会分为男生和女生,按年龄段分组,就会分成多个年龄段的。

        2、用annotate()分组,annotate()之前的是按照什么分组,括号里写的是聚合函数

        3、例子

        如果使用原生的SQL语句,按照部门分组求平均工资:

    select dept,AVG(salary) from employee group by dept;

        ORM查询: 

    from django.db.models import Avg
    Employee.objects.values("dept").annotate(avg=Avg("salary").values("dept", "avg")

        连表查询的分组

        SQL语句查询

    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
    models.Dept.objects.annotate(avg=Avg("employee__salary")).values("name", "avg")

    15、F查询

        F可以动态地获取到一个字段的值

    from django.db.models import F      # 从django数据库中导入F
    models.Book.objects.filter(commnet_num__gt=F('keep_num'))     
    # F('keep_num')动态的获取到'keep_num'的值

        Django支持F()对象之间以及F()对象和常数之间的加减乘除和取模的操作

    models.Book.objects.filter(commnet_num__lt=F('keep_num')*2)

        修改操作也可以使用F函数,比如将每一本书价格+30

    models.Book.objects.all().update(price=F("price")+30)

    16、Q查询

        当查询某些数据需要用到‘或’的时候,就需要Q查询。

        示例:

        1、查询作者名是小狐仙或者小仙女的

    models.Book.objects.filter(Q(authors__name="小仙女")|Q(authors__name="小魔女"))

           2、也可以结合   &   和  |   以及括号分组来进行任意操作。还可以用~进行取反

        查询作者名字是小仙女并且不是2018年出版的书的书名

    >>> models.Book.objects.filter(Q(author__name="小仙女") & ~Q(publish_date__year=2018)).values_list("title")
    <QuerySet [('番茄物语',)]>

    17、事务

        1、什么是事务?

        比如一件事情,有好多步骤,每个步骤组合起来就是一个事务。在django中,用transaction表示。

        2、事务的特点

        只有两种可能,要么生,要么死。一个事务要想成功,就必须是每一个步骤全都成功,如果有一个失败,就全都失败,并将成功的分步骤,全不回退。

        3、示例

    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))
  • 相关阅读:
    2018软工实践之团队选题报告
    2018软工实践作业五之结对作业2
    2018软工实践作业四之团队展示
    2018软工实践作业四之团队展示
    2018软工实践作业三
    职场老鸟项目经理多年感悟
    项目冲突管理
    项目变更如何控制
    项目管理基础
    成功项目管理与PMP认证2017
  • 原文地址:https://www.cnblogs.com/wf123/p/9773840.html
Copyright © 2020-2023  润新知