django ORM框架(操作数据库)第一章

news/2024/10/30 23:19:30/

目录

一、ORM框架介绍

二、Django配置数据库

2.1 在本地mysql中创建数据库与用户

2.2 django 连接本地mysql(安装mysqlclient及依赖环境)mac安装

三、模型类

3.1、创建模型类&生成迁移脚本&执行迁移脚本

3.2 类属性&表字段介绍

3.2.1  models.CharField() 字符串

3.2.2 时间相关:DateTimeField 与DateField

3.2.3 自定义主键 primary_key=True

3.2.4 自定义表名称&内部类&排序

3.2.5 演示 

四、CURD 增删改查

4.1 新增数据 Create

4.2  查询 Read

4.2.1 读取表里所有数据

4.2.2 读取单条数据 (不推荐): 模型类.objects.get(条件1=值1)   

4.2.3 读取多/单条数据(推荐):objects.filter(条件1=值1)

4.2.4   .objects.filter 多种查询类型

4.2.5   .objects.exclude 反向查询 (常用)

五、QuerySet 介绍

六、公共模型类

下一章:


一、ORM框架介绍

ORM框架,把类和数据进行映射,通过类和对象操作它对应表格中的数据,进行增删改查(CRUD)

ORM框架中

数据库:需要提前手动创建数据库

数据表:与OMR框架中的模型类对应

字段:模型类中的类属性(Field子类)

记录:一行数据,多个模型类(字段)的实例。

二、Django配置数据库

2.1 在本地mysql中创建数据库与用户

1、启动本地的mysql

(我的是mac电脑,在系统偏好设置里,点击mysql图标进行启动)

root

123456

2.2 django 连接本地mysql(安装mysqlclient及依赖环境)mac安装

听说win安装mysqlclient 难度挺大,我这里用的mac

1、检查本地是否安装brew。如已经安装,跳过这一步

如果没有安装,则安装brew。安装brew的方法

/bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"

 安装brew方法:

mac 安装 brew 亲测有效_做测试的喵酱的博客-CSDN博客

2、安装mysql-client

我mac本地,安装的mysql 版本是5.7.10 

所以我安装mysql-client 版本也要求为5.7

如果你是【mac】需要安装mysql-client (指定版本)

 brew install mysql-client@5.7

如果你是 【Debian / Ubuntu】

sudo apt-get install python-dev default-libmysqlclient-dev

 如果你是 【Red Hat / CentOS】

sudo yum install python-devel mysql-devel

3、【mac】配置mysql-client的环境变量

找到mysql-client的安装路径,一般为/opt/homebrew/Cellar/mysql-client@5.7/

配置环境变量

vim ~/.zshrc
export PATH="/opt/homebrew/opt/mysql-client@5.7/bin:$PATH"

使环境变量生效: 

source ~/.zshrc

4、本地安装 mysqlclient

pip install mysqlclient

报错处理:

mac 安装 pip install mysqlclient 报错_做测试的喵酱的博客-CSDN博客

5、在数据库中,需要先手动创建一个库

CREATE DATABASE my_django charset=utf8mb4;

6、在settings.py 文件中,DATABASES 配置数据库信息

DATABASES = {'default': {# mysql数据库的引擎'ENGINE': 'django.db.backends.mysql',# 数据库的名称,需要连接mysql下具体某一个数据库的名称'NAME': 'my_django','USER': 'root','PASSWORD': '123456','HOST': '127.0.0.1','PORT': '3306',}
}

三、模型类

1、一般模型类都创建在models.py文件下

2、一个模型类,对应一张表

3、一个类属性,对应表里的一个字段

4、创建表时,会默认创建一个自增主键

类属性与表字段对应关系

类属性表字段
CharFieldvarchar
IntegerFieldint
BooleanFieldbool
TextField长文本

第一步:创建一个模型类

第二步:生成迁移脚本

第三步:执行迁移脚本

3.1、创建模型类&生成迁移脚本&执行迁移脚本

我们以前创建表的时候,是通过sql创建,如

CREATE TABLE table_name 。。。。

现在我们不通过sql,而是通过模型类创建表。

将一个模型类,转换成表。

1、创建一个模型类

类属性,对应数据库表中的字段。

一般模型类都创建在models.py文件下

models.py

from django.db import models# Create your models here.class Animal(models.Model):# 数据库中varchar类型: 可变字符串,与CharField 对应name = models.CharField(max_length=50)# 数据库中int类型:与IntegerField 对应age = models.IntegerField()# bool 类型与 BooleanField 对应gender = models.BooleanField()

2、生成迁移脚本

格式:

python manage.py makemigrations 子应用名称

如果不加子应用名称,则对所有的应用都生成迁移脚本

python manage.py makemigrations

如果只想迁移某一个子应用的数据,要指定子应用名称

 举例:

在pycharm 中的 Terminal下执行

python manage.py makemigrations orders

 在orders/migrations/0001_initial.py 生成了迁移脚本

3、执行迁移脚本

模版:

python manage.py migrate 子应用名称

如果后面不加子应用的名称,则会执行所有应用的迁移脚本。

举例:

我只执行oders应用下的迁移脚本

python manage.py migrate orders

执行完成后,可以去数据库中,看到新增的这个表。

生成的表名为 应用名称_小写的类名

4、扩展:将迁移脚本转成sql语句。

模版:

python manage.py sqlmigrate 应用名称 脚本名称

脚本名称,不需要以.py结尾 

举例:

将orders下的 0001_initial.py 脚本,转成sql

python manage.py sqlmigrate orders 0001_initial

3.2 类属性&表字段介绍

属性介绍
verbose_name=''字段的描述“'字段的描述“,好习惯会加verbose_name
help_text='''字段的描述“'字段的描述“,好习惯会加help_text
blank=True允许输入字段为空
null=True允许输入null
default=xx设置字段的默认值为xx
unique=True设置字段属性唯一

3.2.1  models.CharField() 字符串

1、models.CharField() 必须设置max_length=20

3.2.2 时间相关:DateTimeField 与DateField

DateTimeField 与DateField 特有的属性。

auto_now_add=True记录创建这条数据时的时间
auto_now=True记录这条数据更新时的时间

举例:

一条用户的信息数据,有一个创建时间create_time,和数据更新时间 update_time

 create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间', help_text='创建时间')update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间', help_text='更新时间')

3.2.3 自定义主键 primary_key=True

1、自定义主键 primary_key=True

ids = models.IntegerField(primary_key=True, verbose_name='商品id', help_text='商品id')

在一个模型类中,如果我们没有自定义主键,系统会自动创建一个主键id 。

2、设置自增主键 models.AutoField

id = models.AutoField(primary_key=True, verbose_name='商品id', help_text='商品id')

3.2.4 自定义表名称&内部类&排序

 1、表的名称,默认为 应用名称_小写的类名。

我们想自定义表的名称,通过内部类实现.。

内部类 class Meta:

db_table 是固定写法。

2、表的描述

verbose_name = "商品表"
verbose_name_plural = "商品表"

class Goods(models.Model):ids = models.IntegerField(primary_key=True, verbose_name='商品id', help_text='商品id')# a.CharField类型必须指定max_length参数(改字段的最大字节数)# b.如果需要给一个字段添加唯一约束,unique=True(默认为False)name = models.CharField(max_length=20, verbose_name='商品名称', help_text='商品名称',# h.可以在任意一个模型类中创建Meta内部类,用于修改数据库的元数据信息class Meta:# i.db_table指定创建的数据表名称db_table = 'tb_goods'# 为当前数据表,设置中午呢描述verbose_name = "商品表"verbose_name_plural = "商品表"

3.2.5 演示 

 1、models.py

from django.db import models# Create your models here.class Animal(models.Model):# 数据库中varchar类型: 可变字符串,与CharField 对应name = models.CharField(max_length=50)# 数据库中int类型:与IntegerField 对应age = models.IntegerField()# bool 类型与 BooleanField 对应gender = models.BooleanField()class Goods(models.Model):ids = models.IntegerField(primary_key=True, verbose_name='商品id', help_text='商品id')# a.CharField类型必须指定max_length参数(改字段的最大字节数)# b.如果需要给一个字段添加唯一约束,unique=True(默认为False)name = models.CharField(max_length=20, verbose_name='商品名称', help_text='商品名称',unique=True)channel = models.CharField(max_length=10, verbose_name='商品渠道', help_text='商品渠道')# c.使用default指定默认值(如果指定默认值后,在创建记录时,改字段传递,会使用默认值)on_sale = models.BooleanField(verbose_name='是否在售', help_text='是否在售',default=True)# d.null=True指定前端创建数据时,可以指定该字段为null,默认为null=False,DRF进行反序列化器输入时才有效# e.blank=True指定前端创建数据时,可以指定该字段为空字符串,默认为blank=False,DRF进行反序列化器输入时才有效desc = models.TextField(verbose_name='商品描述', help_text='商品描述',null=True, blank=True, default='')# f.在DateTimeField、DateField等字段中,指定auto_now_add=True,在创建一条记录时,会自动将创建记录时的时间作为该字段的值,后续在更新数据时,就不再修改# g.在DateTimeField、DateField等字段中,指定auto_now=True,在更新一条记录时,会自动将更新记录时的时间作为该字段的值create_time = models.DateTimeField(auto_now_add=True, verbose_name='商品创建时间', help_text='商品创建时间')update_time = models.DateTimeField(auto_now=True, verbose_name='商品更新时间', help_text='商品更新时间')# h.可以在任意一个模型类中创建Meta内部类,用于修改数据库的元数据信息class Meta:# i.db_table指定创建的数据表名称db_table = 'tb_goods'

2、生成迁移脚本

python manage.py makemigrations orders

3、执行迁移脚本

python manage.py migrate orders

4、查看新生成的表

5、查看,将迁移脚本转成sql语句。

python manage.py sqlmigrate orders 0002_goods

四、CURD 增删改查

表中,一行数据(一条记录)就是一个模型类的实例对象。

商品goods的模型类如下:

class Goods(models.Model):ids = models.IntegerField(primary_key=True, verbose_name='商品id', help_text='商品id')# a.CharField类型必须指定max_length参数(改字段的最大字节数)# b.如果需要给一个字段添加唯一约束,unique=True(默认为False)name = models.CharField(max_length=20, verbose_name='商品名称', help_text='商品名称',unique=True)channel = models.CharField(max_length=10, verbose_name='商品渠道', help_text='商品渠道')# c.使用default指定默认值(如果指定默认值后,在创建记录时,改字段传递,会使用默认值)on_sale = models.BooleanField(verbose_name='是否在售', help_text='是否在售',default=True)

4.1 新增数据 Create

在tb_goods表里,新增数据。实现方式,类的实例化

方式一: 模型类(字段名1=1值,字段名2=值2,....)

模版:

    obj=Goods(ids="1",name="电脑",channel="电商")obj.save()

两行代码,先实例化对象,再调用save方法。

注意:模型类的实例,必须调用save()方法,才会去执行sql

举例:

def get_good_1(request):obj=Goods(ids="1",name="电脑",channel="电商")obj.save()return HttpResponse("传入一条数据")

配置url

path('get_good_1',views.get_good_1)

启动服务,调用接口:

http://127.0.0.1:8000/orders/get_good_1

表里新增了一条数据

方式二:模型类.objects.create(字段名1=1值,字段名2=值2,....)

模板:

Goods.objects.create(ids="2",name="鼠标",channel="线下")

举例:

def get_good_2(request):Goods.objects.create(ids="2",name="鼠标",channel="线下")return HttpResponse("创建第二条数据")

接口调用该方法,数据库成功新增一条数据

4.2  查询 Read

提前造一批数据,供查询演示

BEGIN;
INSERT INTO `tb_goods` (`ids`, `name`, `channel`, `on_sale`, `desc`, `create_time`, `update_time`) VALUES (1, '电脑', '电商', 1, '', '2023-05-16 09:26:00.350727', '2023-05-16 09:26:00.350855');
INSERT INTO `tb_goods` (`ids`, `name`, `channel`, `on_sale`, `desc`, `create_time`, `update_time`) VALUES (2, '鼠标', '线下', 1, '', '2023-05-16 09:29:52.101118', '2023-05-16 09:29:52.101482');
INSERT INTO `tb_goods` (`ids`, `name`, `channel`, `on_sale`, `desc`, `create_time`, `update_time`) VALUES (3, '插排', '电商', 1, '', '2023-05-16 09:40:30.336316', '2023-05-16 09:40:30.336393');
INSERT INTO `tb_goods` (`ids`, `name`, `channel`, `on_sale`, `desc`, `create_time`, `update_time`) VALUES (4, '充电线', '线下', 1, '', '2023-05-16 09:40:32.963407', '2023-05-16 09:40:32.963456');
INSERT INTO `tb_goods` (`ids`, `name`, `channel`, `on_sale`, `desc`, `create_time`, `update_time`) VALUES (5, '显示器', '电商', 1, '', '2023-05-16 09:41:10.128975', '2023-05-16 09:41:10.129023');
INSERT INTO `tb_goods` (`ids`, `name`, `channel`, `on_sale`, `desc`, `create_time`, `update_time`) VALUES (6, '耳机', '线下', 1, '', '2023-05-16 09:41:07.905568', '2023-05-16 09:41:07.905732');
INSERT INTO `tb_goods` (`ids`, `name`, `channel`, `on_sale`, `desc`, `create_time`, `update_time`) VALUES (7, '可乐', '电商', 1, '', '2023-05-16 09:41:44.799209', '2023-05-16 09:41:44.799275');
INSERT INTO `tb_goods` (`ids`, `name`, `channel`, `on_sale`, `desc`, `create_time`, `update_time`) VALUES (8, '雪碧', '线下', 1, '', '2023-05-16 09:41:42.566164', '2023-05-16 09:41:42.566487');
INSERT INTO `tb_goods` (`ids`, `name`, `channel`, `on_sale`, `desc`, `create_time`, `update_time`) VALUES (9, '笔记本', '电商', 1, '', '2023-05-16 09:42:17.367187', '2023-05-16 09:42:17.367240');
INSERT INTO `tb_goods` (`ids`, `name`, `channel`, `on_sale`, `desc`, `create_time`, `update_time`) VALUES (10, '主机', '线下', 1, '', '2023-05-16 09:42:15.143852', '2023-05-16 09:42:15.144253');
COMMIT;

4.2.1 读取表里所有数据

模板:

模型类.objects.all()

模型类.objects.all() 的返回结果,是将模型类对应的表,表里的所有数据都读出来。

注意,模型类.objects.all() 的返回结果是一个QuerySet对象(查询集对象)

QuerySet 查询集特性:

1、QuerySet对象,类似于列表,具有惰性查询的特性。在调用 模型类.objects.all()=QuerySet对象 时,是不会真正的去执行sql。 当具体去用数据时,才会执行sql语句。

举例:

查询集合

4.2.2 读取单条数据 (不推荐): 模型类.objects.get(条件1=值1)   

方式一

模版:

 qs = 模型类.objects.get(条件1=值1)
# 获取一行数据中,某个字段的值
变量名=qs.类属性名

举例:

tb_goods表中,ids="1"的数据

def get_read_2(request):qs = Goods.objects.get(ids="1")# 获取一行数据中,某个字段的值name = qs.namechannel = qs.channel

注意:

1、 qs = Goods.objects.get(ids="1") 取出来的数据,qs 的type= <class 'orders.models.Goods'>

就是一个Goods的实例对象。 如果想获取具体某个字段的值,对象.属性名 就可以了

2、使用 模型类.objects.get(条件1=值1)    获取到的数据,必须只能是一条数据。

2.1如果返回结果是多条数据,会抛出异常。 比如查询

Goods.objects.get(name="电脑")

的数据,表里有多条name=电脑的数据,则使用objects.get 获取的数据大于1条,则会抛出异常。

2.2 如果查询条件,没有命中任何数据,也会抛出异常。 比如查询 ids="100"的数据,但是表里不存在ids="100"的数据,则也会抛出异常

所以在使用objects.get 的方法时,要注意try..catch..捕获异常

3、为了保证查询结果,只有一条数据符合条件,在使用条件查询时,最好使用具有唯一约束的条件去查询。比如id 之类的

4.2.3 读取多/单条数据(推荐):objects.filter(条件1=值1)

模版:

qs = 模型类.objects.filter(条件)

1、qs = Goods.objects.filter(ids="1")

返回结果,qs的类型是 QuerySet

2、查询结果无数据时,返回一个空的QuerySet对象

3、获取查询集QuerySet 中的第一条数据

Goods.objects.filter(ids="1")[0] 或者Goods.objects.filter(ids="1").frist()

4、获取查询集QuerySet 的长度

len(Goods.objects.filter(ids="1"))

或者

Goods.objects.filter(ids="1").count()

5、 QuerySet 支持for循环

举例:

def get_read_3(request):qs = Goods.objects.filter(ids="1")res=qs[0]return HttpResponse(qs)

4.2.4   .objects.filter 多种查询类型

1、对字符串查询处理

模版:

字段名__查询类型=具体值

  • 字段名__startswith:以xxx开头
  • 字段名__istartswith:以xxx开头(忽略大小写)
  • 字段名__endswith:以xxx结尾
  • 字段名__isnull:是否为null
  • 字段名__contains:包含
  • 字段名__icontains:包含(忽略大小写)
  • 在列表之内:字段名__in=[xx,xxx]

举例:

查询Student表中,姓名 name ,以姓“张”开头的学生

Students.objects.filter(name__startswith="张")

查询Student表中,姓名 name 中,包含“红” 的姓名信息

Students.objects.filter(name__contains="红")

 Student表中,查询age 年龄 为 16岁  19 岁学生的信息

Students.objects.filter(age__in=[16,19])

2、对数字查询处理

模版:

字段名__查询类型=具体值

  • 大于 gt (greate than) :字段名__gt
  • 小于 lt (less than): 字段名__lt
  • 等于 e (equal): 字段名__e
  • 大于等于 :字段名__gte

举例:

Student表中,查询age 年龄大于等于18的学生信息

Students.objects.filter(age__gte=18)

4.2.5   .objects.exclude 反向查询 (常用)

objects.exclude 与 objects.filter 是相反的,但是查询类型是一模一样的。

举例:

 查询Student表中,姓名 name ,查询 非姓“张”同学的信息

Students.objects.exclude(name__startswith="张")

查询Student表中,姓名 name 中,不包含“红” 的姓名的学生信息

Students.objects.exclude(name__contains="红")

五、QuerySet 介绍

# TODO

六、公共模型类

当我们有多个模型类,其中有很多重复字段时,我们可以把公共的字段提出来,封装成一个公共的类。

举例:

如 order_id 、order_name 两个字段,属于公共字段,很多模型类都会用到。将它封装成公共模型类

1、公共模型类

class BaseModel(models.Model):order_id = models.CharField(max_length=10,verbose_name='订单id', help_text='订单id')order_name = models.CharField(max_length=10,verbose_name='订单名称', help_text='名称')class Meta:# 在内部类Meta中,一旦指定abstract = True,那么当前模型类为抽象模型类,在迁移时不会创建表,仅仅是为了供其他类继承abstract = True

注意:

内部类下,的 abstract=True 。在内部类Meta中,一旦指定abstract = True,那么当前模型类为抽象模型类,在迁移时不会创建表,仅仅是为了供其他类继承

2、继承

当需要用到这公共字段时,直接继承 公共内部类就可以了。

class Test(BaseModel):

下一章:

django ORM框架 第二章 表与表的关系&关联表_做测试的喵酱的博客-CSDN博客


http://www.ppmy.cn/news/70206.html

相关文章

Python每日一练(20230514) 不同路径 I\II\III UniquePaths

目录 1. 不同路径 I Unique Paths 1 2. 不同路径 II Unique Paths 2 3. 不同路径 III Unique Paths 3 &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日一练 专栏 1. 不同路径 I Unique Paths 1 一个…

PyCaret:低代码自动化的机器学习工具

PyCaret简介 随着ChatGPT和AI画图的大火&#xff0c;机器学习作为实现人工智能的底层技术被大众越来越多的认知&#xff0c;基于机器学习的产品也越来越多。传统的机器学习实现方法需要较强的编程能力和数据科学基础&#xff0c;这使得想零基础尝试机器学习变得非常困难。 机器…

哈希表应用——位图

应用场景&#xff1a;海量数据处理&#xff08;这里的海量是指一般数据量非常大如以亿为单位的数据量&#xff09; 目录 面试题 位图概念 位图的实现 位图的应用 应用一 应用二 位图应用变形 面试题 给40亿个不重复的无符号整数&#xff0c;没排过序。给一个无符号整数&…

【组合数学】全错位排列的递推公式推导

简介 假设现在我有三个信封A&#xff0c;B&#xff0c;C&#xff0c;并且现在有三个信纸a&#xff0c;b&#xff0c;c。 按照道理的话是&#xff0c;a塞入A信封&#xff0c;b塞入B信封&#xff0c;c塞入C信封。 但是现在&#xff0c;想要问&#xff0c;对于a&#xff0c;b&…

[JavaScript]JSON对象

eval函数 eval函数能将一个字符串当做一段JS代码解释并执行。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name&quo…

什么是Java中的阻塞队列?它有什么作用?

在Java中&#xff0c;阻塞队列是一种特殊的队列&#xff0c;它可以在队列为空或队列已满时阻塞添加或移除元素的操作。阻塞队列通常用于多线程编程中&#xff0c;可以帮助我们更加方便地进行线程通信和协作。在本文中&#xff0c;我将从面试的角度&#xff0c;详细讲解Java中的…

深入篇【C++】类与对象:运算符重载详解

深入篇【C】类与对象&#xff1a;运算符重载详解 ⏰一.运算符重载&#x1f553;1.<运算符重载&#x1f550;2.>运算符重载&#x1f552;3.运算符重载&#x1f551;4.运算符重载①.格式1.改进12.改进2 ②.默认成员函数1.功能2.不足 &#x1f553;5.<运算符重载&#x1…

什么是MQTT,和MQ有什么区别

什么是MQTT&#xff0c;和MQ有什么区别 概述常用的软件和MQ的主要区别应用场景 概述 MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;是一种轻量级的发布/订阅消息传输协议&#xff0c;主要用于物联网&#xff08;IoT&#xff09;领域&#xff0c;特别是在网…