当前位置 博文首页 > 小杨-先生:Django-ORM-单表操作

    小杨-先生:Django-ORM-单表操作

    作者:小杨-先生 时间:2021-06-13 18:22

    目录
    • 一、ORM介绍
    • 二、单表操作
      • 表创建
      • 新增记录
      • 删除记录
      • 修改记录
    • 三、查询API
    • 四、基于双下滑线的模糊查询

    一、ORM介绍

    ORM是(对象-关系-映射)的简称:它实现了数据模型与数据库的解耦,对于数据库的操作,就不用去写原生的 SQL 语句,取而代之的是基于面向对象的思想去编写类、对象、调用相应的方法等,ORM 会将其转换成对应的原生 SQL 语句交给 pymysql 执行。

    直接编写原生的 SQL 语句会存在两个方面的问题:

    1. SQL 语句的执行效率:应用开发程序员需要耗费一大部分精力去优化 SQL 语句。
    2. 数据库迁移:针对 mysql 开发的 SQL 语句无法直接应用到 oracle 数据库上,一旦迁移数据库,需要考虑夸平台的问题。

    原生 SQL 和 python 的 ORM 代码对比。

    原生 SQL 操作:

    # 创建表
    create table student(
        id int primary key auto_increment,
        name varchar(20) not null,
        age int default 18 not null,
        birthday date not null
    );
    
    # 新增记录
    insert into student(name,age,birthday)
    	values ('小杨',18,'1998-11-1');
    	
    # 删除记录
    delete from student where id=1;
    
    # 更新记录
    update student set birthday='1999-12-22' where id=1;
    
    # 查询记录
    select * from student;
    

    ORM 的 python 类,和对象

    # 类创建表
    class Student(models.Model):
        id = models.AutoField(primary_key=True)
        name = models.CharField(max_length=20)
        age = models.IntegerField(default=18)
        birthday = models.DateField()
        
    # 新增记录
    obj = Student(name='小杨', birthday='1928-2-6')
    obj.save()
    
    # 删除记录
    Student.objects.filter(id=1).delete()
        
    # 更新记录
    Student.objects.filter(id=2).update(birthday='2000-3-22')
    
    # 查询记录
    obj = models.Student.objects.filter(id=2)
    

    二、单表操作

    在python中的ORM的对应关系有三种:

    类:————> 表

    类对象:——> 一行数据

    类属性:——> 字段

    表创建

    在创建表之前需要做好如下配置

    1、必须事先创建好数据库

    2、在 settings.py 文件中的 DATABASES 配置项中增加或者修改成如下配置

    DATABASES = {
        # 这是默认的数据库
        'default': {
            'ENGINE': 'django.db.backends.mysql',	# 使用mysql数据库
            'HOST': '127.0.0.1',			# mysql服务器主机IP
            'USER': 'root',					# 链接数据库的用户名
            'PASSWORD': '123',				# 链接数据库的密码
            'PORT': 3306,					# mysql监听端口
            'NAME': 'orm',					# 要链接的数据库(必须先创建)
            'ATOMIC_REQUEST': True,			# True 代表同一个http请求所对应的所有SQL都放在一个事物中
            								# 执行(要么所有都成功,要么所有都失败),这是全局配置
        }
        # 也可以为每个app都配置自己的数据库,并且数据库还可以是别的数据库
        'app01': {
            'ENGINE': 'django.db.backends.sqlite',	# 使用sqlite数据库
            'HOST': '127.0.0.1',			
            'USER': 'root',					
            'PASSWORD': '123',				
            'PORT': 3306,					
            'NAME': 'orm',					
            'ATOMIC_REQUEST': True,	
    	}
    }
    

    3、在Django项目下的__init__.py文件中写入这样一句话,因为Django的ORM底层操作数据库的python模块默认是 mysqldb 而非 pymysql ,而python三支持的是 pymysql 模块,所以要修改默认操作数据库的模块:

    # __init__.py 文件
    import pymysql
    pymysql.install_as_MySQLdb()
    

    4、在 Django中 app项目里的 models.py 文件中创建模型

    from django.db import models
    
    # 创建表
    class Student(models.Model):					# 表名——> app名_Student
        id = models.AutoField(primary_key=True)		# 字段id
        name = models.CharField(max_length=20)		# 字段name
        age = models.IntegerField(default=18)		# 字段age
        birthday = models.DateField()				# 字段birthday
    

    5、最后在命令行中执行这两条数据库迁移命名,就可以在指定的数据库 orm 中创建表:

    $ python manage.py makemigrations
    $ python manage.py migrate
    
    注意:
    1、makemigrations 只是生成一个数据库迁移记录的文件,而 migrate 才是将更改真正提交到数据库执行
    2、数据库迁移记录的文件存放于app01下的 migrations 文件夹里
    3、了解:使用命令 python manage.py showmigrations 可以查看没有执行 migrate 的文件
    

    新增记录

    视图函数中对表进行操作

    # views.py 文件
    from django.shortcuts import HttpResponse
    from app01 import models    # 导入需要操作的表
    
    
    def index(request):
        """
        :param request: http请求信息
        :return: 响应信息/页面
        对表的操作:如下:插入一条记录
        """
        obj = models.Student(name='波波', birthday='2010-5-21')
        obj.save()
        return HttpResponse('Hello World...')
    

    创建记录方式一:

    obj = models.Student(
        name='波波', 
        birthday='2010-5-21'
    )
    obj.save()	# 就是pymysql的commit提交
    

    创建记录方式二:create方法(用的多)

    date = datetime.datetime.now()	# 当前时间
    # birthday字段可以给时间类型数据
    obj = models.Student.objects.create(name='艾伦', birthday=date)
    # 可以基于这个对象来取属性的值
    print(obj.name)
    
    #------------------------------------------
    dic1 = {'name': '大鱼', 'age': 10, 'birthday': '1998-9-24'}
    obj = models.Student.objects.create(**dic1)
    
    """
    表单数据如下:
    <QueryDict: {'csrfmiddlewaretoken': ['20..sUe'], 'user': ['123']}>
    
    可以把表单提交的数据转成字典 request.POST.dict()
    {'csrfmiddlewaretoken': '20...sUe', 'user': '123'}
    
    在作用于create数据操作上
    
    """
    

    创建记录方式三:批量创建

    objs_list = []
    for i in range(10):
        obj = models.Student(
            name='xiaoyang',
            age=20+i,
            birthday='2010-3-9'
        )
        objs_list.append(obj)	
    models.Student.objects.bulk_create(objs_list)	# 批量插入,速度快
    

    创建记录方式四:update_or_create 有就更新,没有就创建

    models.Student.objects.update_or_create(
        id=10, 			# 筛选条件
        defaults={		# 添加或更新的数据
            'name': '超人',
            'age': 40,
            'birthday': '2001-9-3',
        }
    )
    

    删除记录

    删除 delete :queryset 和 model 对象都可以调用

    # 删除id=14的记录
    models.Student.objects.filter(id=14).delete()	# ---> queryset 对象
    # 删除所有记录
    models.Student.objects.filter().delete()		# ---> queryset 对象
    
    models.Student.objects.get(id=14).delete()		# ---> model 对象
    

    修改记录

    更新update方法model对象不能调用更新方法:

    只能queryset对象调用:

    # 修改id=13的name字段和age字段
    models.Student.objects.filter(id=13).update(name='牛牛', age=20)
    

    三、查询API

    • all( )

    查询所有结果,结果是queryset类型

    obj = models.Student.objects.all()
    print(obj)
    # 输出	queryset集合,类似于列表
    """
    在类中加入__str__方法:方便如下查看
    def __str__(self):
    	return self.name
    """
    <QuerySet [<Student: 小红>, <Student: 波波>, <Student: 艾伦>, <Student: 牛牛>]>
    
    • filter(**kwargs)

    返回的也是queryset集合,查询不到内容不会报错,返回一个<Queryset []>空的queryset,里面可以加入多个条件,用逗号分开,是and关系。

    obj = models.Student.objects.filter(id=4)   # 找到id=4的那条记录
    print(obj)	# ——> <QuerySet [<Student: 艾伦>]>
    
    • get(**kwargs)

    返回的是行记录(model)对象,而且get方法有且必须只有一个结果

    obj = models.Student.objects.get(id=4)      # 找到id=4的那条记录
    print(obj)	# ——> 艾伦
    
    • exclude(**kwargs)

    排除的意思,筛选调价不匹配的对象,没有不等于的操作,返回一个queryset对象

    # 返回id不等于1的所有对象
    models.Student.objects.filter().exclude(id=1)
    
    • order_by(*field)

    queryset类型的数据来调佣,对查询结果排序,默认是按照id来升序排列的,返回值还是queryset对象类型

    models.Student.objects.filter().order_by('price', id)
    
    # 直接写price默认是按照price升序排列
    # 按照字段降序排列,就写个负号就行了order_by('-price')
    # order_by('price','id')是多条件排序
    # 按照price进行升序,price相同的数据,按照id进行升序
    
    • reverse()

    queryset类型的数据来调用,对查询结果反向排序,返回值是queryset类型

    # 排序之后反转
    models.Student.objects.all().arder_by('id').revers()
    
    • count()

    queryset类型的数据来调用,返回数据库中匹配查询(QuerySet)的对象数量。

    models.Student.objects.filter().count()
    
    • first()

    queryset类型的数据来调用,返回第一条记录,结果是model对象

    models.Student.objects.filter().first()
    
    • last()

    queryset类型的数据来调用,返回最后一条记录,结果是model对象

    models.Student.objects.filter().last()
    
    • exists()

    queryset类型的数据来调用,如果QuerySet包含数据,就返回True,否则返回False

    models.Student.objects.all().exists()
    
    • values(*field)

    queryset类型的数据来调用返回一个ValuesQuerySet--一个特殊的QuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典列,只要是返回的queryset类型,就可以继续链式调用queryset类型的其他查找方法,其他方法也是一样的。

    obj1 = models.Student.objects.filter().values()
    obj2 = models.Student.objects.values('name')
    print(obj1)		
    # <QuerySet [{'id': 2, 'name': '小红', 'age': 18, 'birthday': ...},{...},...]>
    
    print(obj2)
    <QuerySet [{'name': '小红'}, {'name': '波波'}, {'name': '艾伦'}]>
    
    • values_list(*field)

    它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列。

    obj1 = models.Student.objects.filter().values_list()
    obj2 = models.Student.objects.values_list('name')
    print(obj1)
    # <QuerySet [(2, '小红', 18, datetime.date(2000, 3, 22)), (3, '波波', 18, datetime.date(2010, 5, 21)), (4, '艾伦', 18, datetime.date(2021, 6, 10))]>
    
    print(obj2)
    # <QuerySet [('小红',), ('波波',), ('艾伦',)]>
    
    • distinct()

    从values或values_list的返回结果中剔除重复的记录对象,返回值为QuerySet对象

    models.Student.objects.values_list('name').distinct()
    

    四、基于双下滑线的模糊查询

    Book.objects.filter(price__in=[100,200,300]) 	# price值等于这三个里面的任意一个的对象
    Book.objects.filter(price__gt=100)  			# 大于,大于等于是price__gte=100,别写price>100,这种参数不支持
    Book.objects.filter(price__lt=100)
    Book.objects.filter(price__range=[100,200])  	# sql的between and,大于等于100,小于等于200
    Book.objects.filter(title__contains="python")  	# title值中包含python的
    Book.objects.filter(title__icontains="python") 	# 不区分大小写
    Book.objects.filter(title__startswith="py") 	# 以什么开头,istartswith  不区分大小写
    Book.objects.filter(pub_date__year=2012)
    

    日期查询示例:

    all_books = models.Book.objects.filter(pub_date__year=2012) 	# 找2012年的所有书籍
    all_books = models.Book.objects.filter(pub_date__year__gt=2012)	# 找大于2012年的所有书籍
    
    all_books = models.Book.objects.filter(pub_date__year=2019,pub_date__month=2)
    # 找2019年月份的所有书籍,如果明明有结果,你却查不出结果,是因为mysql数据库的时区和咱们django的时区不同导致的,了解一下就行了,你需要做的就是将django中的settings配置文件里面的USE_TZ = True改为False,就可以查到结果了,以后这个值就改为False,而且就是因为咱们用的mysql数据库才会有这个问题,其他数据库没有这个问题。
    
    bk