Python主流框架Django,ORM框架

数据模型的增删改查

一、 框架基本介绍

O是object,也就类对象的意思,R是relation,翻译成中文是关系,也就是关系数据库中数据表的意思,M是mapping,是映射的意思。在ORM框架中,它帮我们把类和数据表进行了一个映射,可以让我们通过类和类对象就能操作它所对应的表格中的数据。ORM框架还有一个功能,它可以根据我们设计的类自动帮我们生成数据库中的表格,省去了我们自己建表的过程。

ORMDjango框架中的使用

django中内嵌了ORM框架,不需要直接面向数据库编程,而是定义模型类,通过模型类和对象完成数据表的增删改查操作。

  • 使用 django 框架进行数据库开发的步骤

    • 配置数据库连接信息
    • models.py中定义模型类
    • 数据库迁移
    • 通过操作类和对象完成对数据的增删改查操作

二、ORMDjango中的使用步骤

1-创建工程并修改配置参数

2-安装并注册应用 books

3-配置数据库连接信息

安装MySQL数据库驱动程序

python 复制代码
pip install PyMySQL

在Django的工程同名子目录的__init__.py文件中添加如下语句,作用是让Django的ORM能以MySQLdb的方式来调用pyMySQL

python 复制代码
from pymysql import install_as_MySQLdb
​
install_as_MySQLdb()

在工程配置文件settings.py中修改DATABASES的配置信息

python 复制代码
# django支持多数据库操作,在数据库迁移时默认使用 'default'数据库,想要在迁移时指定使用的数据库见【附2: ORM补充】
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'HOST': '127.0.0.1',  # 数据库主机
        'PORT': 5000,  # 数据库端口
        'USER': 'django',  # 数据库用户名
        'PASSWORD': 'django',  # 数据库用户密码
        'NAME': 'django_demo'  # 数据库名字
    },
    'bak': {
        'ENGINE': 'django.db.backends.mysql',
        'HOST': '127.0.0.1',  # 数据库从机
        'PORT': 5000,  # 数据库端口
        'USER': 'django',  # 数据库用户名
        'PASSWORD': 'django',  # 数据库用户密码
        'NAME': 'django_demo_bak'  # 数据库名字
    },
    
}

修改配置

python 复制代码
DATABASES = {
    "default": {
        'ENGINE': 'dj_db_conn_pool.backends.mysql',
        'HOST': '127.0.0.1',  # 数据库主机
        'PORT': 5000,  # 数据库端口
        'USER': 'django',  # 数据库用户名
        'PASSWORD': 'django',  # 数据库用户密码
        'NAME': 'django_demo'  # 数据库名字
        'POOL_OPTIONS': {
            'POOL_SIZE': 10,  # 最小
            'MAX_OVERFLOW': 10,  # 在最小的基础上,还可以增加10个,即:最大20个。
            'RECYCLE': 24 * 60 * 60,  # 连接可以被重复用多久(单位:秒),超过会重新创建,-1表示永久。
            'TIMEOUT':30, # 池中没有连接最多等待的时间(单位:秒)。
        }
    }
}

在MySQL创建数据库

python 复制代码
create database django_demo default charset=utf8;

使用root账户为这个项目创建一个MySQL管理员账户,管理项目相关的数据库

python 复制代码
# 当前ubuntu虚拟机的mysql数据库root密码为:Root123
# 创建用户账号 django, 密码 django (由identified by 指明)
create user django identified by 'django'; 
​
# 授权django_demo数据库下的所有表(django_demo.*)的所有权限(all)给用户django在以任何ip访问数据库('django'@'%')
grant all on django_demo.* to 'django'@'%'; 
​
# 刷新生效用户权限
flush privileges;

4-在books应用下的 models.py 文件中定义模型类

  • 4.1 - 模型类定义规

  • 模型类如果未指明表名,Django默认以 "小写app应用名_小写模型类名" 为数据库表名。可通过在模型类中嵌套定义一个类名为 "Meta" 的类, 并在Meta类中通过类属性 db_table 指明数据库表名.

  • 数据库表名

    • 关于主键 django会为表创建自动增长的主键列,每个模型只能有一个主键列,如果使用选项设置某属性为主键列后django不会再创建自动增长的主键列。 默认创建的主键列属性为id,可以使用pk(primary key)代替
  • 4.2 - 属性命名限制

    • 不能是python的保留关键字。

    • 不允许使用连续的下划线,这是由Django的查询方式决定的。

    • 定义属性时需要指定字段类型,通过字段类型的参数指定选项,语法如下属性=models.字段类型(选项)

  • 4.3 - 字段类型

    类型 说明
    AutoField 自动增长的IntegerField,通常不用指定,不指定时Django会自动创建属性名为id的自动增长属性
    BooleanField 布尔字段,值为True或False
    NullBooleanField 支持Null、True、False三种值
    CharField 字符串,参数max_length表示最大字符个数
    TextField 大文本字段,一般超过4000个字符时使用
    IntegerField 整数
    DecimalField 十进制浮点数, 参数max_digits表示总位数, 参数decimal_places表示小数位数
    FloatField 浮点数
    DateField 日期, 参数auto_now表示每次保存对象时,自动设置该字段为当前时间,用于"最后一次修改"的时间戳,它总是使用当前日期,默认为False; 参数auto_now_add表示当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为False; 参数auto_now_add和auto_now是相互排斥的,组合将会发生错误
    TimeField 时间,参数同DateField
    DateTimeField 日期时间,参数同DateField
    FileField 上传文件字段
    ImageField 继承于FileField,对上传的内容进行校验,确保是有效的图片
  • 4.4 - 选项

    选项 说明
    verbose_name 用于设置该字段在Django管理后台中显示的人类可读的名称。通常用于提供更友好、可读性更强的字段名,以便开发者和管理员更容易理解字段的用途。
    null 如果为True,表示允许为空,默认值是False
    blank 如果为True,则该字段允许为空白,默认值是False
    db_column 字段的名称,如果未指定,则使用属性的名称
    db_index 若值为True, 则在表中会为此字段创建索引,默认值是False
    default 默认
    primary_key 若为True,则该字段会成为模型的主键字段,默认值是False,一般作为AutoField的选项使用
    unique 如果为True, 这个字段在表中必须有唯一值,默认值是False
    max_length 字符长度;必选项
    auto_now_add 创建时,自动生成时间
    auto_now 更新时,自动更新为当前时间
    choices 一个用来选择值的2维元组。第一个值是实际存储的值,第二个用来方便进行选择。如SEX_CHOICES= (('F', 'Female'), ('M','Male'),)
    • null是数据库范畴的概念,blank是表单验证范畴的
  • 4.5 - 外键

  • 在设置外键时,需要通过on_delete选项指明主表删除数据时,对于外键引用表数据如何处理,在django.db.models中包含了可选常量:

    • CASCADE 级联,删除主表数据时连同一起删除外键表中数据

    • PROTECT 保护,通过抛出**ProtectedError**异常,来阻止删除主表中被外键应用的数据

    • SET_NULL 设置为NULL,仅在该字段null=True允许为null时可用

    • SET_DEFAULT 设置为默认值,仅在该字段设置了默认值时可用

    • SET() get_or_create作用 get_user_model作用 设置为特定值或者调用特定方法,如

python 复制代码
  from django.conf import settings
  from django.contrib.auth import get_user_model
  from django.db import models
  
  def get_sentinel_user():
      return get_user_model().objects.get_or_create(username='deleted')[0]
  
  class MyModel(models.Model):
      user = models.ForeignKey(
          settings.AUTH_USER_MODEL,
          on_delete=models.SET(get_sentinel_user),
      )
5-以**【图书-英雄管理】** 为例进行 模型类定义与使用演示
  • 创建应用books ,在models.py 文件中定义模型类。

    python 复制代码
    from django.db import models
    ​
    #定义图书模型类BookInfo
    class BookInfo(models.Model):
        btitle = models.CharField(max_length=20, verbose_name='名称')
        bpub_date = models.DateField(verbose_name='发布日期')
        bread = models.IntegerField(default=0, verbose_name='阅读量')
        bcomment = models.IntegerField(default=0, verbose_name='评论量')
        is_delete = models.BooleanField(default=False, verbose_name='逻辑删除')
        
        class Meta:
            # 指明数据库表名
            db_table = 'tb_books'
            # 在admin站点中显示的名称
            verbose_name = '图书'
            # 显示的复数名称
            verbose_name_plural = verbose_name
            
        def __str__(self):
            """定义每个数据对象的显示信息"""
            return self.btitle
        
        
    #定义英雄模型类HeroInfo
    class HeroInfo(models.Model):
        GENDER_CHOICES = (
            (0, 'male'),
            (1, 'female')
        )
        hname = models.CharField(max_length=20, verbose_name='名称') 
        hgender = models.SmallIntegerField(choices=GENDER_CHOICES, default=0, verbose_name='性别')  
        hcomment = models.CharField(max_length=200, null=True, verbose_name='描述信息') 
        hbook = models.ForeignKey(BookInfo, on_delete=models.CASCADE, verbose_name='图书')  # 外键
        is_delete = models.BooleanField(default=False, verbose_name='逻辑删除')
        
        class Meta:
            db_table = 'tb_heros'
            verbose_name = '英雄'
            verbose_name_plural = verbose_name
            
        def __str__(self):
            return self.hname
  • 数据库迁移

    • 数据库迁移说明

    • 进行数据库迁移的目的是将模型类同步到数据库中。makemigrations 命令查找所有可用的模型,为任意一个在数据库中不存在对应数据表的模型创建迁移脚本文件。migrate 命令则运行这些迁移来自动创建数据库表。还提供可选的更丰富的控制模式。

    • 生成迁移文件

      python 复制代码
      python manage.py makemigrations
    • 数据库迁移

      python 复制代码
      python manage.py migrate
      # 指定连接的数据库,默认为default
      python manage.py migrate --database=default
      python manage.py migrate --database=bak
      # 指定迁移的应用
      python manage.py migrate app01 --database=default
      添加测试数据
      
      添加图书数据
      
      
      
      
      
      insert into tb_books(btitle,bpub_date,bread,bcomment,is_delete) values
      ('射雕英雄传','1980-5-1',12,34,0),
      ('天龙八部','1986-7-24',36,40,0),
      ('笑傲江湖','1995-12-24',20,80,0),
      ('雪山飞狐','1987-11-11',58,24,0);
      添加英雄数据
      
      
      
      
      
      insert into tb_heros(hname,hgender,hbook_id,hcomment,is_delete) values
      ('郭靖',1,1,'降龙十八掌',0),
      ('黄蓉',0,1,'打狗棍法',0),
      ('黄药师',1,1,'弹指神通',0),
      ('欧阳锋',1,1,'蛤蟆功',0),
      ('梅超风',0,1,'九阴白骨爪',0),
      ('乔峰',1,2,'降龙十八掌',0),
      ('段誉',1,2,'六脉神剑',0),
      ('虚竹',1,2,'天山六阳掌',0),
      ('王语嫣',0,2,'神仙姐姐',0),
      ('令狐冲',1,3,'独孤九剑',0),
      ('任盈盈',0,3,'弹琴',0),
      ('岳不群',1,3,'华山剑法',0),
      ('东方不败',0,3,'葵花宝典',0),
      ('胡斐',1,4,'胡家刀法',0),
      ('苗若兰',0,4,'黄衣',0),
      ('程灵素',0,4,'医术',0),
      ('袁紫衣',0,4,'六合拳',0);
6-通过类和对象完成数据增删改查操作
  • shell 工具的使用

    复制代码
    Django的manage工具提供了shell命令,帮助我们配置好当前工程的运行环境(如连接好数据库等),以便可以直接在终端中执行测试python语句。
    • 在终端(Terminal)中进入shell交互环境

      python 复制代码
      python manage.py shell
    • 导入两个模型类,以便后续使用

      python 复制代码
      from books.models import BookInfo, HeroInfo
  • 查看MySQL数据库日志

    • 查看mysql数据库日志可以查看对数据库的操作记录。 mysql日志文件默认没有产生,需要做如下配置:

      python 复制代码
      sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf
    • 把68,69行前面的#去除,然后保存并使用如下命令重启mysql服务

      复制代码
      # 跳转到指定行: 在命令行模式下输入":行数"
      复制代码
      sudo service mysql restart
    • 使用如下命令打开mysql日志文件。

      复制代码
      # 实时查看数据库的日志内容
      复制代码
      sudo tail -f /var/log/mysql/mysql.log 
  • 数据库 增、删、改、查

    • 1 - 增加

      • 使用说明

        复制代码
        增加数据有两种方法。
        复制代码
        方式一: 通过创建模型类对象,执行对象的save()方法保存到数据库中。
        复制代码
        方式二: 通过模型类.objects.create()保存。
        复制代码
        ​**可通过IDE自带的数据库插件连接数据库; 方便查看数据库数据变化、执行SQL语句
      • 代码示例

        python 复制代码
        >>> from datetime import date
        >>> book = BookInfo(
            btitle='西游记',
            bpub_date=date(1988,1,1),
            bread=10,
            bcomment=10
        )
        >>> book.save()
        >>> hero = HeroInfo(
            hname='孙悟空',
            hgender=0,
            hbook=book
        )
        >>> hero.save()
        >>> hero2 = HeroInfo(
            hname='猪八戒',
            hgender=0,
            hbook_id=book.id
        )
        >>> hero2.save()
        ​
        ​
        >>> # 指定数据库: HeroInfo.objects.using("bak").create()
        >>> HeroInfo.objects.create(
            hname='沙悟净',
            hgender=0,
            hbook=book
        )
        <HeroInfo: 沙悟净>
        ​
        >>> # 批量创建; batch_size 指定一次性提交的数量
        >>> HeroInfo.objects.bulk_create(
            objs=[
                HeroInfo(hname='红孩儿',hgender=0,hbook=book),
                HeroInfo(hname='铁扇公主',hgender=0,hbook=book)
            ],
            batch_size=3
        )
        [<HeroInfo: 红孩儿>, <HeroInfo: 铁扇公主>]
    • 2 - 查询

      • 2.1-基本查询

        • 查询规则:

          复制代码
          1. get 查询单一结果,如果不存在会抛出模型类 .DoesNotExist 异常,查询到多条数据会抛出MultipleObjectsReturned异常
          复制代码
          2. all 查询多个结果。
          复制代码
          3. count 查询结果数量。
          复制代码
          4. values 与 values_list 查询指定字段的所有值
        • 代码示例:

          python 复制代码
          >>> BookInfo.objects.all()
          <QuerySet [<BookInfo: 射雕英雄传>, <BookInfo: 天龙八部>, <BookInfo: 笑傲江湖>, <BookInfo: 雪山飞狐>, <BookInfo: 西游记>]>
          ​
          >>> book = BookInfo.objects.get(btitle='西游记')
          >>> book.id
          5
          ​
          >>> BookInfo.objects.all().values('btitle')
          >>> BookInfo.objects.all().values_list('btitle')
          >>> HeroInfo.objects.all().values('hbook_id').distinct()
          ​
          >>> BookInfo.objects.get(id=3)
          <BookInfo: 笑傲江湖>
          >>> BookInfo.objects.get(pk=3)
          <BookInfo: 笑傲江湖>
          ​
          >>> BookInfo.objects.get(id=100)
          """
          Traceback (most recent call last):
          File "<console>", line 1, in <module>
          File "/Users/delron/.virtualenv/dj/lib/python3.6/site-packages/django/db/models/manager.py", line 85, in manager_method
          return getattr(self.get_queryset(), name)(*args, **kwargs)
          File "/Users/delron/.virtualenv/dj/lib/python3.6/site-packages/django/db/models/query.py", line 380, in get
          self.model._meta.object_name
          db.models.DoesNotExist: BookInfo matching query does not exist.
          """

          >>> BookInfo.objects.count()

      • 2.2-过滤查询

        • 查询规则

          复制代码
          1. filter 过滤出多个结果
          复制代码
          2. exclude 排除掉符合条件剩下的结果
          复制代码
          3. get 过滤单一结果
        • 过滤条件的使用语法

          复制代码
          # 属性名称和比较运算符间使用两个下划线,所以属性名不能包括多个下划线
          复制代码
          属性名称__比较运算符=值
        • 代码演练

          • 相等 exact:表示判等

            复制代码
            # 查询编号为1的图书。
            复制代码
            BookInfo.objects.filter(id__exact=1)
            复制代码
            # 可简写为:
            复制代码
            BookInfo.objects.filter(id=1)
          • 模糊查询

            • 使用语法

            • contains:是否包含(如果要包含 "%" 无需转义,直接写即可)

              复制代码
              startswith、endswith:以指定值开头或结尾。
              复制代码
              说明: 以下运算符都区分大小写,在这些运算符前加上i表示不区分大小写,如iexact、icontains、istartswith、iendswith.
            • 代码示例

              复制代码
              # 查询书名包含'传'的图书。
              复制代码
              BookInfo.objects.filter(btitle__contains='传')
              复制代码
              # 查询书名以'部'结尾的图书
              复制代码
              BookInfo.objects.filter(btitle__endswith='部')
          • 空查询 isnull:是否为null。

            复制代码
            # 查询书名不为空的图书
            复制代码
            BookInfo.objects.filter(btitle__isnull=False)
          • 范围查询 in:是否包含在范围内

          • 查询编号为1或3或5的图书

            复制代码
            BookInfo.objects.filter(id__in=[1, 3, 5])
          • 比较查询

            • 使用语法gt 大于 (greater then)

            • gte 大于等于 (greater then equ)

            复制代码
            lt 小于 (less then)
            复制代码
            lte 小于等于 (less then equal)
            复制代码
            exclude  不等于的运算符,使用exclude()过滤器
            • 代码示例

            • 查询编号大于3的图书

              BookInfo.objects.filter(id__gt=3)

              查询编号不等于3的图书

              BookInfo.objects.exclude(id=3)

          • 日期查询 year、month、day、week_day、hour、minute、second:对日期时间类型的属性进行运算。# 查询1980年发表的图书。BookInfo.objects.filter(bpub_date__year=1980)

            查询1990年1月1日后发表的图书。BookInfo.objects.filter(bpub_date__gt=date(1990, 1, 1))

相关推荐
abandondyy1 小时前
MySQL---主从复制和读写分离
数据库·mysql
Narutolxy1 小时前
探索开源语音识别的未来:高效利用先进的自动语音识别技术20241030
python·macos·xcode
DEARM LINER2 小时前
mysql 巧妙的索引
数据库·spring boot·后端·mysql
Mopes__3 小时前
Python | Leetcode Python题解之第517题超级洗衣机
python·leetcode·题解
码农幻想梦3 小时前
实验九 视图的使用
前端·数据库·oracle
影子落人间3 小时前
Oracle创建存储过程,创建定时任务
数据库·oracle
大G哥3 小时前
02、Oracle过滤和排序数据
数据库·oracle
代码吐槽菌5 小时前
基于SSM的汽车客运站管理系统【附源码】
java·开发语言·数据库·spring boot·后端·汽车
测试老哥5 小时前
Python+Selenium+Pytest+POM自动化测试框架封装(完整版)
自动化测试·软件测试·python·selenium·测试工具·职场和发展·测试用例
Ws_5 小时前
蓝桥杯 python day01 第一题
开发语言·python·蓝桥杯