Django框架之ORM

1,字段和字段的参数

1.1>ORM的概念:对象映射模型(Objects Relational Model)是一种为了解决面向对象和关系型数据库存在的互不匹配的现象和技术,简单的说,ORM是通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系数据库中,ORM是连接业务逻辑和关系型数据库的桥梁

1.2>ORM的由来

  在程序开发人员中,需要一边写业务逻辑部分的内容,有要一遍边写sql语句的增删改查,这就造成程序开发人员的开发效率不够高,错误漏洞会百出,sql语句特点是极其相似的或者重复的,这样的背景下就衍生出来了ORM

1.3>ORM的优势:

  ORE解决了对象和关系型数据库的映射关系,类和表一一对应

  我们不用再去操作数据库,直接操作类就好了,同过ORM把操作类转化成操作数据库

  提高了软件开发人员的开发效率

1.4>ORM的劣势

  在一定程度上降低了程序的执行效率

  ORM只能操作表,且在操作表的时候 也是有有限的操作,一些复杂的查询依旧无法完成

  Mysql数据库的操作技能的不到加强

1.5>总之:

  ORM是业务逻辑和数据库之间的纽带,他能完成一些简单的,繁琐的操作,一些特殊的问题还是无法完成,遇到特殊情况特殊处理

2,Django中的ORM

2.1>Django中ORM的配置

  1>手动创建一个数据库

  2>在settings.py文件中DATABASES 种设置 

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.mysql",  # 告诉Django用mysql数据库
        "NAME": "db2",  # 指定数据库的名字 
        "HOST": "127.0.0.1",  # 指定主机地址
        "PORT": 3306,  # 指定端口号
        "USER": "root",  # 指定用于类型
        "PASSWORD": "123456",  # 指定密码
    }
}

  3>在和settings同级的__init__文件中导入pymysql

    import pymysql

    pymysql.install_as_MySQLdb()

  4>在新建的APP包中的models.py中创建类

  5>在Terminal中输入变更命令

    python manage.py makemigrations  # 把models中的变更记录到APP文件下的migrations中,并且每次有变更就会新生成一个.py文件,且每当新创建项目的时候,生成的py文件名是一样的,它会默认是一个新的项目,如果使用了之前的数据库和表,需要把migrations中的变更文件copy过来

    python manage.py migrate  # 把变更的文件转化成mysql语句,去操作数据库

  或者:在tool中找到run manage.py task

    输入命令: makemigrations   

         migrate

  6>测试mysql数据库

2.2>Model

  在Model中我们通过创建类来生成数据库中的表

  类  <--------------------------->  表

  属性    <--------------------------->  表中的字段

  对象    <--------------------------->  数据行

2.3>常用字段

  2.3.1>AutoField:自增的整形字段,必填参数primary_key = True,则成为数据库的主键,无该字段是,Django会帮我们自动创建.注意,一个model中不能包含2个AutoField字段

  2.3.2>IntegerField:表示是整数类型,数值范围是+/-10(-2147483648~2147483647)

  2.3.3>CharField:对应数据库中的varchar类型(不定长)需要指定最大的长度max_length参数

  2.3.4>DateField:日期类型,格式:YYYY-MM-DD,相当于python中的datetime.date(年:月:日)

      参数:auto_now:每次修改时,修改为当前时间,

        auto_now_add:新创建对象时自动添加当前日期时间,

        auto_now和auto_now_add是互斥的,不能同时设置,也可以不设置,手动的去修改

  2.3.5>DatetimeField:日期时间字段,格式为YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ](年:月:日:时:分:秒)

 AutoField(Field)
        - int自增列,必须填入参数 primary_key=True

    BigAutoField(AutoField)
        - bigint自增列,必须填入参数 primary_key=True

        注:当model中如果没有自增列,则自动会创建一个列名为id的列
        from django.db import models

        class UserInfo(models.Model):
            # 自动创建一个列名为id的且为自增的整数列
            username = models.CharField(max_length=32)

        class Group(models.Model):
            # 自定义自增列
            nid = models.AutoField(primary_key=True)
            name = models.CharField(max_length=32)

    SmallIntegerField(IntegerField):
        - 小整数 -32768 ~ 32767

    PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
        - 正小整数 0 ~ 32767

    IntegerField(Field)
        - 整数列(有符号的) -2147483648 ~ 2147483647

    PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
        - 正整数 0 ~ 2147483647

    BigIntegerField(IntegerField):
        - 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807

    BooleanField(Field)
        - 布尔值类型

    NullBooleanField(Field):
        - 可以为空的布尔值

    CharField(Field)
        - 字符类型
        - 必须提供max_length参数, max_length表示字符长度

    TextField(Field)
        - 文本类型

    EmailField(CharField):
        - 字符串类型,Django Admin以及ModelForm中提供验证机制

    IPAddressField(Field)
        - 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制

    GenericIPAddressField(Field)
        - 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
        - 参数:
            protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
            unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启此功能,需要protocol="both"

    URLField(CharField)
        - 字符串类型,Django Admin以及ModelForm中提供验证 URL

    SlugField(CharField)
        - 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)

    CommaSeparatedIntegerField(CharField)
        - 字符串类型,格式必须为逗号分割的数字

    UUIDField(Field)
        - 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证

    FilePathField(Field)
        - 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
        - 参数:
                path,                      文件夹路径
                match=None,                正则匹配
                recursive=False,           递归下面的文件夹
                allow_files=True,          允许文件
                allow_folders=False,       允许文件夹

    FileField(Field)
        - 字符串,路径保存在数据库,文件上传到指定目录
        - 参数:
            upload_to = ""      上传文件的保存路径
            storage = None      存储组件,默认django.core.files.storage.FileSystemStorage

    ImageField(FileField)
        - 字符串,路径保存在数据库,文件上传到指定目录
        - 参数:
            upload_to = ""      上传文件的保存路径
            storage = None      存储组件,默认django.core.files.storage.FileSystemStorage
            width_field=None,   上传图片的高度保存的数据库字段名(字符串)
            height_field=None   上传图片的宽度保存的数据库字段名(字符串)

    DateTimeField(DateField)
        - 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]

    DateField(DateTimeCheckMixin, Field)
        - 日期格式      YYYY-MM-DD

    TimeField(DateTimeCheckMixin, Field)
        - 时间格式      HH:MM[:ss[.uuuuuu]]

    DurationField(Field)
        - 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型

    FloatField(Field)
        - 浮点型

    DecimalField(Field)
        - 10进制小数
        - 参数:
            max_digits,小数总长度
            decimal_places,小数位长度

    BinaryField(Field)
        - 二进制类型
View Code

在ORM中没有char类型等,ORM值提供了有限的数据类型,有些类型需要我们自己定义

2.4>自定义一个char类型的字段

  在APP下的model里边直接创建char类 ,并执行变更的命令

只要在models文件中有变更就要执行变更命令,加入有1,2的选项就是新增字段需要设置默认值

2.5>常见字段的参数说明:

 1 字段参数
 2 字段参数,详情可点击查看官网。
 3 1
 4 2
 5 3
 6 4
 7 5
 8 6
 9 7
10 8
11 9
12 10
13 11
14 12
15 13
16 14
17 15
18 16
19 17
20 18
21 19
22 20
23 21
24 22
25 23
26 24
27 25
28 26
29 27
30 28
31 29
32 30
33 31
34 32
35 33
36 34
37 35
38 36
39 37
40 38
41 39
42 40
43     null                数据库中字段是否可以为空
44     db_column           数据库中字段的列名
45     default             数据库中字段的默认值
46     primary_key         数据库中字段是否为主键
47     db_index            数据库中字段是否可以建立索引
48     unique              数据库中字段是否可以建立唯一索引
49     unique_for_date     数据库中字段【日期】部分是否可以建立唯一索引
50     unique_for_month    数据库中字段【月】部分是否可以建立唯一索引
51     unique_for_year     数据库中字段【年】部分是否可以建立唯一索引
52  
53     verbose_name        Admin中显示的字段名称
54     blank               Admin中是否允许用户输入为空
55     editable            Admin中是否可以编辑
56     help_text           Admin中该字段的提示信息
57     choices             Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
58                         如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)
59  
60     error_messages      自定义错误信息(字典类型),从而定制想要显示的错误信息;
61                         字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date
62                         如:{'null': "不能为空.", 'invalid': '格式错误'}
63  
64     validators          自定义错误验证(列表类型),从而定制想要的验证规则
65                         from django.core.validators import RegexValidator
66                         from django.core.validators import EmailValidator,URLValidator,DecimalValidator,\
67                         MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator
68                         如:
69                             test = models.CharField(
70                                 max_length=32,
71                                 error_messages={
72                                     'c1': '优先错信息1',
73                                     'c2': '优先错信息2',
74                                     'c3': '优先错信息3',
75                                 },
76                                 validators=[
77                                     RegexValidator(regex='root_\d+', message='错误了', code='c1'),
78                                     RegexValidator(regex='root_112233\d+', message='又错误了', code='c2'),
79                                     EmailValidator(message='又错误了', code='c3'), ]
80                             )
81  
82 字段参数
其它字段的参数

2.6>表中Meta参数的说明

3,ORM查询13种方法

import os
if __name__ == '__main__':
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day_67.settings")
    import django
    django.setup()
    from app01.models import Classroom, Teacher, Student, Person
    # for el in obj:
    #     print(el.name)
        # print(el.phone)
        # print(el.get_gender_display())
    # 1,all()查询到该表的所有对象      --->对象列表
    # obj1 = Classroom.objects.all()
    # for el in obj:
    #     print(el.name)
    # 2,get  -->拿到的是一个对象
    # 查询不到就会报错,获取多个也会报错
    # obj2 = Classroom.objects.get(id=1)
    # print(obj2.name)
    # 3,filter,查询所有满足条件的对象   --->对象列表
    # obj3 = Classroom.objects.filter(name="python14脱产班")
    # for el in obj3:
    #     print(el.name)
    # 4,exclude 查询出所有不满足条件的对象    --->对象列表
    # obj5 = Classroom.objects.exclude(name="python14脱产班")
    # for el in obj5:
    #     print(el.id)
    # 5,value查询出所有具体每一个对象的数据        ------->列表对象里包含字典
    # obj6 = Classroom.objects.all().values()
    # for el in obj6:
    #     print(el)
    # 5.1value查询出指定的对象的具体信息         ----->对象列表里包含字典
    # obj7 = Classroom.objects.all().values("id")
    # for el in obj7:
    #     print(el)
    # 6,value_list取具体的数据        ------>对象列表里包含元组(只有value没有key)
    # 没有指定参数获取的是锁有字段的数据
    # obj8 = Classroom.objects.all().values_list()
    # for el in obj8:
    #     print(el)
    # 指定参数,获取指定字段数据
    # obj9 = Classroom.objects.all().values_list("id","name")  # 获取到的是元组
    # for el in obj9:
    #     print(el)
    # 7,order_by 排序,可以指定多个字段
    # obj10 = Classroom.objects.all().order_by("-id")  # 先拿到所有对象,再排序
    # for el in obj10:
    #     print(el.id)
    # obj11 = Person.objects.all().order_by("age","-id")  # 在字段前边加符号就是倒序
    # for el in obj11:
    #     print(el.id)
    # obj12 = Classroom.objects.all().distinct("name")  # 也许列个对象完全一样才能去重
    # for el in obj12:
    #     print(el)
    # 8,count()计数
    # obj13 = Classroom.objects.all().count()
    #     # print(obj13)
    #     # obj14 = Classroom.objects.filter(id=2).count()
    #     # print(obj14)
    # 9,first()当拿到的是一个 queryset对象的时候去first()是去第一个对象
    # obj15 = Classroom.objects.all()
    # print(obj15.first().name)
    # 10,first()当取到单一对象的时候就会报错,必须获得的是一个queryset
    # obj16 = Classroom.objects.get(id=3)
    # print(obj16.first())
    # 11,last()依旧
    # 12,exists()判断是否返回布尔值,只能判断queryset对象列表
    obj17 = Classroom.objects.all().exists()
    print(obj17)
    '''
    返回对象列表的方法
    all()
    filter()
    exclude()
    order_by()
    reverse()
    distinct()
    values()  { }
    values_list()  ( )
    
    返回对象的方法
    get()
    first()
    last()
    create()
    
    返回布尔值
    exists()
    
    返回数字
    coun()
    '''
ORM查询的13种方法

 4,单表的查询和双下方法

import os
if __name__ == '__main__':
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day_67.settings")
    import django
    django.setup()
    from app01.models import Person, Classroom, Teacher, Student
    # obj1 = Person.objects.filter(id__gt=1)  # great than 大于
    # for el in obj1:
    #     print(el.name)
    # obj2 = Person.objects.filter(id__lt=2)  # less than 小于
    # for el in obj2:
    #     print(el.name)
    # obj3 = Person.objects.get(id__lt=2)  # 当用get的时候,返回尽可能缩小到一个对象才会生效
    # print(obj3.age,obj3.name)
    # obj4 = Person.objects.filter(id__gte=3)  # id值大于等于3的所有对象集合
    # for el in obj4:
    #     print(el.name)
    # obj5 = Person.objects.filter(id__lte=2)  # less than equal id值小于等于2
    # for el in obj5:
    #     print(el.name)
    # obj6 = Person.objects.filter(id__in=[3,5])  # id值等于3和5的对象集合
    # for el in obj6:
    #     print(el.id,el.name)
    # obj7 = Person.objects.filter(id__in=[3,10])  # 只包括id=3和id10
    # for el in obj7:
    #     print(el.id,el.name)
    # obj8 = Person.objects.filter(id__gte=1, id__lte=3)
    # for el in obj8:
    #     print(el.id,el.name)
    # obj9 = Person.objects.filter(id__range=[1,3])  # 范围从1到3,左右都包括
    # for el in obj9:
    #     print(el.id,el.name)
    # obj10 = Person.objects.filter(name__contains="无")  # 中文也识别,包含contain 返回的是一个queryset
    # for el in obj10:
    #     print(el.id,el.name)
    # obj11 = Person.objects.filter(name__icontains="无")  # ignore contains 表示忽略大小写
    #     # for el in obj11:
    #     #     print(el.id,el.name)
    # obj12 = Person.objects.filter(name__endswith="忌")  # 以什么结尾 拿到的是queryset
    # for el in obj12:
    #     print(el.id,el.name)
    # obj13 = Person.objects.filter(name__startswith="张")  # 以什么开始
    # print(obj13)
    # obj14 = Person.objects.filter(birth__year=2018)
    #     #     # print(obj14[0].id,obj14[0].name)
    obj15 = Person.objects.filter(birth__year=1997)
    obj16 = obj15.filter(birth__month=10)
    print(obj16,type(obj16))
    obj17 = Person.objects
    print(obj17,type(obj17))
    obj18 = Person.objects.filter(birth__month=1997-10)
    print(obj18,type(obj18))
    obj19 = Person.objects.filter(birth__year=1997,birth__month=10,birth__day=11)
    print(obj19,type(obj19))

5,外键的查询

import os

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

    django.setup()
    from app01.models import Classroom, Student, Teacher

    # 基于对象的查询(多对一)
    # student_obj = Student.objects.get(id=2)
    # print(student_obj.name)
    # print(student_obj.id)
    # print(student_obj.classroom)
    # print(student_obj.classroom_id)
    # 正想查询
    # obj_id = Classroom.objects.get(name="python15脱产班").id
    # print(obj_id)  # 先找到班级的id,随便拿一个有效的id值
    # obj1 = Student.objects.filter(classroom_id= obj_id)  # 匹配班级id用的
    # print(obj1[0].id,obj1[0].name)
    # 双下方法可以使用values出来的是一个字典根据字典的key值去拿到值
    # obj2 = Student.objects.all().values("id","name","classroom_id","classroom__name")
    # print(obj2)
    # value_list拿到是一个元组用索引去取某一个值
    # obj4 = Student.objects.all().values_list("id", "name", "classroom__name")
    # for el in obj4:
    #     print(el[0],el[1],el[2])
    # for el in obj2:
    #     print(el["id"],el["name"],el["classroom__name"])
    # 可以用双下方法来通过外键直接查找到关联表的所有信息
    # obj3 = Student.objects.filter(classroom__name="python14脱产班")
    # for el in obj3:
    #     print(el.name,el.id,el.classroom__name)

    # 反向查询
    # obj5 = Classroom.objects.get(id=3)
    #     print(obj5)
    #     #     print(obj5.student_set.all())
    #     #     obj6 = obj5.student_set.all()  # student_set是在model中的外键relate_name = "student_set"默认设置
    #     #     for el in obj6:
    #     #         print(el.name,el.id)
    # obj7 = Classroom.objects.filter(id=Student.objects.get(name="康琛").classroom_id)
    # for el in obj7:
    #     print(el.id,el.name)
    obj8 = Classroom.objects.get(id=1)  # 现获取到班级id=4的对象
    # obj8.student_set.set(Student.objects.filter(id__in=[3,4]))  # 通过student_set方向查询到id =3和id=4的对象,并修改外键关联为1
    # obj8.student_set.add(Student.objects.filter(id__in=[5,6]))  # 追加,
    # obj8.student_set.remove(Student.objects.filter(id__in=[5,6]))  # 需要在model中的该字段设置为可以为空

小结:正向查询的时候,通过外键或的关联表的相应对象,可以同过外键查找到关联表的所有属性

  反向查询的时候就不能通过外键查询了,1>先要获取到班级的对象,2>再使用student_set(relate_name= "students"时就换成students)这次可以获取到学生的所有对象的到是一个queryset对象列表

6,多对多查询

import os
if __name__ == '__main__':
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day_67.settings")
    import django
    django.setup()
    from app01.models import Teacher, Classroom, Student
    # 获取到教师的id=3的对象
    obj1 =  Teacher.objects.get(id=3)
    print(obj1.name)

    # obj1.students.add(*Student.objects.all())
    # obj1.students.add(1,2,3)  # add是有数据表中有了数据就不加了,没有才会增加
    # 当添加有重复的数据.重复的不会再增加,原先没有的才会增加
    # obj1.students.set([1,2,3,4])  # 也是给多对多表添加学生,当数据存在的时候,也就不会再设置了,没有就会设置
    # obj1.students.remove(*Student.objects.all())  # 移除教师对象id=3的所有数据
    # obj1.students.clear()  # 把获取到教室id=3对象的所有数据删除
    obj1.students.create(name="雪雪",classroom_id=7)    
    # 这个可以指定已经存在的数据,也可以不存在的数据,不论存在与否,都会在第三张表新增数据,且学生表也会增加数据
    # classroom_id也会新增,只有,最开始的班级表不会新增数据

小结:多对多表的修改只是在第三张表的操作,遵循增删改查

  增:add()有就会覆盖(id值是变化的),没有就会增加

   create(参数)创建该对象的对应关系数据,关联id可以存在,也可以不存在,当不存在的时候,在学生表也会生成相应的数据,只有班级表不会增加数据

  删:remove(可以指定参数),删除第三张表的所有对象,原表并没有发生变化

   clear()括号不加参数参数,清空该对象与关联的所有数据

  改:set(),会把获取到的对象的原来的值设置成set里边的一一对应关系 

  查:.all()查询所有该对应关系的数据 

  

  

猜你喜欢

转载自www.cnblogs.com/ljc-0923/p/9806210.html