Django配置数据库&ORM基础字段&选项&增删改查&F对象Q对象&聚合查询&原生数据库操作&SQL注入

前置条件

  1. MySQL已安装

  2. 安装pip3 install mysqlclient. #是对C语言操作MySQL数据库的一个简单封装支持Python3

  3. 安装不上mysqlclient的话,pip3 install pymysql #纯Python实现的一个驱动. 用pymysql的话需要伪装成mysqlclient(因为Django源代码要求mysqlclient),伪装方法:在项目的__init__.py文件里添加如下配置

    python 复制代码
    import pymysql
    pymysql.version_info = (1, 4, 13, "final", 0)
    pymysql.install_as_MySQLdb()

创建数据库

  • create database 数据库名 default charset utf8
  • 通常数据库名称跟项目名称一致

Django配置数据库

  • setttings.py里数据库具体配置如下

    python 复制代码
    # Database
    # https://docs.djangoproject.com/en/4.2/ref/settings/#databases
    
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'pmms',  # 数据库名称
            'HOST': '127.0.0.1',  # 数据库地址,本机 ip 地址 127.0.0.1
            'PORT': 3306,  # 端口
            'USER': 'root',  # 数据库用户名
            'PASSWORD': 'BuNengGaoSuNi',  # 数据库密码
        }
    }

模型介绍

  • 模型是一个Python类,它是由django.db.models.Model派生出来的子类。
  • 一个模型类代表数据库中的一张数据表。
  • 模型类的一个对象代表数据表的一行数据。
  • 模型类中的每一个类属性都代表数据库中的一个字段。
  • 模型是数据交互的接口,是表示和操作数据库的方法。

ORM介绍

ORM(Object Relational Mapping)即对象关系映射,它是一种程序技术,允许你使用类和对象对数据库进行操作,从而避免通过SQL语句操作数据库。

模型类代码示例

python 复制代码
class AbilityScore(models.Model):
    index = models.AutoField("Index", auto_created=True, primary_key=True)
    employee_id = models.CharField("EmployeeID", max_length=10)
    ability_id = models.IntegerField("AbilityID")
    approved_value = models.CharField("ApprovedValue", max_length=2)
    upcoming_value = models.CharField("UpcomingValue", max_length=2)
    create_time = models.DateTimeField("CreateTime", auto_now_add=True)
    update_time = models.DateTimeField("UpdateTime", auto_now=True)

    class Meta:
        db_table = 'ability_score'

模型类之字段选项

  • 字段选项,指定创建的列的额外信息(如列不只有数据类型还有长度、自增等)
  • 多个选项之间使用逗号,隔开
  1. primary_key 设置为True则数据表不会自动创建id字段,默认False
  2. blank 设置为True时,Django admin管理后台填写数据表时该项值可以不填,不是数据库里的是否可为空。
  3. null 该列值是否允许为空,默认False。建议null=False和default来配合使用,而不是null=True
  4. default 所在列默认值。
  5. db_index 普通索引,声明当前字段要不要添加索引,True/False
  6. unique 唯一索引,设置为True,表示该字段的值不能重复。
  7. db_column 指定列的名称,如果不指定的话则采用属性名作为列名
  8. verbose_name 设置此字段在admin界面上的显示名称(如在后台设置中文名啦对维护更友好。)
  • 好习惯:修改了字段选项【添加或更改】均要makemigrations migrate

模型类-Meta类(内部类)

使用内部Meta类来给模型赋予属性,Meta类下有很多内建的类属性,可对模型来做一些控制。

用于控制表的属性,如表名。改了Meta类也要makemigrations migrate

但凡模型类发生变化都要makemigrations migrate

python 复制代码
class Meta:
        db_table = 'ability_score'

migration 文件不要在代码里追踪。

ORM-管理器对象

ORM CRUD核心->模型类自带的管理器对象

管理器对象:每个继承自Models.Model的模型类,都会有一个objects对象同样被继承下来,即管理器对象。

数据库的增删改查可以通过模型的管理器实现

python 复制代码
class MyModel(models.Model):
    ...
MyModel.objects.create(...) # objects 即管理器对象

Django Shell

在Django提供了一个交互式的操作项目叫Django Shell它能够在交互模式用项目工程的代码(如数据的连接配置和已有的model类),加载当前的项目环境,执行相应的操作。

利用Django Shell可以代替编写view的代码来进行直接操作

注意:项目代码发生变化时,重新进入Django Shell

启动方式:python3 manage.py shell

python 复制代码
python.exe .\manage.py shell
Python 3.9.0 (tags/v3.9.0:9cf6752, Oct  5 2020, 15:23:07) [MSC v.1927 32 bit (Intel)] on win32 
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> 

ORM-插入操作

Django ORM使用一种直观的方式把数据库表中的数据表示成Python对象。

创建数据中每一条记录就是创建一个数据对象

方案一(Prefered):直接使用管理器对象objects 进行create

python 复制代码
MyModel.objects.create(属性1=值1, 属性2=值2, ...)
python 复制代码
models.AbilityScore.objects.create(employee_id=employee_id, ability_id=ability_id,
                                   upcoming_value=upcoming_value)

成功:返回创建好的实体对象

失败:抛出异常

方案二:创建MyModel实例对象,并调用save()进行保存。

python 复制代码
obj = MyModel(属性1=值1,属性2=值2)
obj.属性=值
obj.save()

ORM-查询操作

  • 数据库的查询需要使用管理器对象进行
  • 通过MyModel.objects管理器方法调用查询方法

|-----------|-----------------------|--------------------------------------------|
| 管理器方法 | 说明 | 用法 |
| all() | 查询全部记录,返回QuerySet查询对象 | MyModel.objects.all() select * from table |
| get() | 查询符合条件的单一记录 | |
| filter() | 查询符合条件的多条记录 | |
| exclude() | 查询符合条件之外的全部记录 | |
| ... | | |

values('列1','列2'..)

  • 用法:MyModel.objects.values(...)
  • 作用:查询部分列的数据并返回,等同于select 列1,列2 from xxx
  • 返回值:QuerySet
    • 返回查询结果容器,容器内存字典,每个字典代表一条数据
    • 格式{'列1':值1, '列2':值2}

values_list('列1','列2'..)

  • 用法:MyModel.objects.value_list(...)
  • 作用:返回元组形式的查询结果,等同于select 列1,列2 from xxx
  • 返回值:QuerySet
    • 返回查询结果容器,容器内部存放元组<----和values('列1','列2'..)的差别
    • 格式[(值1),(值2)]和参数顺序一致

order_by()

  • 用法:MyModel.objects.order_by('-列1','列2')
  • 作用:等同于select * from table + ORDER_BY,即隐含了all()方法·
复制代码
```python
python.exe .\manage.py shell
Python 3.9.0 (tags/v3.9.0:9cf6752, Oct  5 2020, 15:23:07) [MSC v.1927 32 bit (Intel)] on win32 
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from ability_score.models import AbilityScore
>>> AbilityScore.objects.order_by('-upcoming_value') 
<QuerySet [<AbilityScore: AbilityScore object (1)>, <AbilityScore: AbilityScore object (2)>]> 
>>> a = AbilityScore.objects.order_by('-upcoming_value')
>>> for item in a:                              
...     print(item.ability_id, item.upcoming_value) 
...  
1 4 
2 2
>>>
```
  • 说明:默认升序,在属性名前增加'-'表示降序。
  • 也可以先all() 方法,获得QuerySet对象后再调用order_by()方法,不过有的多此一举。
复制代码
```python
>>> all = AbilityScore.objects.all() 
>>> items = all.order_by('upcoming_value')
>>> for item in items:
...     print(item.ability_id, item.upcoming_value) 
...  
2 2 
1 4
>>>
```
  • QuerySet对象的query属性可以查看具体SQL语句
复制代码
```python
>>> print(all.query) 
SELECT `ability_score`.`Index`, `ability_score`.`EmployeeID`, `ability_score`.`AbilityID`, `ability_score`.`ApprovedValue`, `ability_score`.`Upcomi
ngValue`, `ability_score`.`CreateTime`, `ability_score`.`UpdateTime` FROM `ability_score`
>>> print(items.query) 
SELECT `ability_score`.`Index`, `ability_score`.`EmployeeID`, `ability_score`.`AbilityID`, `ability_score`.`ApprovedValue`, `ability_score`.`Upcomi
ngValue`, `ability_score`.`CreateTime`, `ability_score`.`UpdateTime` FROM `ability_score` ORDER BY `ability_score`.`UpcomingValue` ASC
>>> for item in items:                              
...     print(item.query)
...  
Traceback (most recent call last): 
  File "<console>", line 2, in <module>
AttributeError: 'AbilityScore' object has no attribute 'query'
>>>
```

filter(条件)

  • 语法:MyModel.objects.filter(属性1=值1,属性2=值2)
  • 作用:返回包含此条件的全部的数据集
  • 返回值:QuerySet容器对象,内部存放MyModel实例
  • 说明:属性1=值1,属性2=值2为"与"的关系
复制代码
```python
if models.AbilityScore.objects.filter(employee_id=employee_id, ability_id=ability_id):
```

exclude(条件)

  • 语法:MyModel.objects.exclude(属性1=值1,属性2=值2)
  • 作用:返回不包含此条件的全部的数据集

get(条件)

  • 语法:MyModel.objects.get(条件)
  • 作用:返回满足条件的唯一一条数据,即模型类的一个对象。
  • 说明:该方法只能返回一条数据。
    • 多于一条,抛Model.MultipleObjectsReturned异常
    • 查询结果没有,抛Model.DoesNotExist异常
    • 就是这么有性格!单条数据首选get()方法
复制代码
```python
employee_ability = models.AbilityScore.objects.get(employee_id=employee_id, ability_id=ability_id)
            if employee_ability.upcoming_value != str(upcoming_value):
                employee_ability.upcoming_value = upcoming_value
                employee_ability.save()
```

查询谓词

  • 定义:做更灵活的条件查询时需要使用查询谓词

  • 说明:每一个查询谓词是一个独立的查询功能

  • __exact:等值匹配

    • 等值匹配__exact,比较精准的场景是匹配NULL,如查询当前字段是空的有哪些,转换IS NULL SQL语句
    • 示例:
    python 复制代码
    Authors.objects.filter(id__exact=1)
    # 等同于select * from author where id = 1
复制代码
### __contains: 包含指定值

* 示例:

  ```python
  Author.objects.filter(name__contanins='w')
  # 等同于 select * from author where name like '%w%'
  ```
复制代码
### __startswith:以XXX开始即SQL里XXX%
复制代码
### __endwith:以XXX结束即SQL里%XXX
复制代码
### __gt:大于指定值

* 示例:

  ```python
  Author.objects.filter(age__gt=50)
  # 等同于 select * from author where age > 50
  ```

__gte:大于等于

__lt:小于

__lte:小于等于

__in:查找数据是否在指定范围内

  • 示例:

    python 复制代码
    Author.objects.filter(country__in=['中国','日本','韩国'])
    # 等同于 select * from author where country in ('中国','日本','韩国')

__range:查找数据是否在指定的区间范围内

  • 示例

    python 复制代码
    Author.objects.filter(age__range=(35,50))
    # 等同于 SELECT ... WHERE AGE BETWEEN 35 AND 50;

ORM-更新操作

单条数据更新

1.查-通过 objects.get() 得到要修改的实体对象

python 复制代码
employee_ability = models.AbilityScore.objects.get(employee_id=employee_id, ability_id=ability_id)

2.改-通过 对象.属性 的方式修改数据

python 复制代码
employee_ability.upcoming_value = upcoming_value

3.保存-通过对象.Save()保存数据

python 复制代码
employee_ability.save()

批量数据更新

直接调用QuerySet的update(property=value)实现批量修改

python 复制代码
# 将 id大于3的所有图书价格定位0元
books = Book.objects.filter(id__gt=3)
books.update(price=0)
# 将所有书的零售价定为100元
books = Book.objects.all()
books.update(market_price=100)

ORM-删除操作

单条数据删除

  1. 查找查询结果对应的一个数据对象

  2. 调用这个数据对象的delete()方法实现删除

    python 复制代码
    try: # 防止没查到 get 太硬报异常
        auth = author.objects.get(id=1)
        auth.delete()
    except:
        print('删除失败')

批量数据删除

  1. 查找查询结果集中满座条件的全部QuerySet查询集合对象

  2. 调用查询集合对象的delete方法实现删除

    python 复制代码
    # 删除全部作者中,年龄大于65的全部信息
    auths = Author.objects.filter(age__gt=65)
    auths.delete()

伪删除

  • 通常不会轻易在业务里把数据真正删掉,取而代之的是做伪删除,即在表中添加一个布尔型字段(is_active),默认是True;

  • 执行删除时将预删除数据的is_active字段置为False

  • 注意:用伪删除时,确保显示数据的地方,均需要添加is_active=True的过滤查询

    python 复制代码
    book = Book.objects.get(id=book_id, is_active=True)
  • 通常的做法是数据伪删除一段时间后,会编写一脚本夜里把is_active=False的数据删除

F对象

  • 一个F对象代表数据库表中某条(也可多条)记录的字段的信息

  • 作用:

    • 通常是对数据库中的字段值在不获取的情况下进行操作
    • 用于类属性(字段)之间的比较
    • 借助于InnoDB写入更新数据时有行锁的功能保证每次只有一人更新数据解决并发问题
    • F对象不做取值操作,只是引用列名,最后该包含F对象的python语句转会为SQL语句
  • 语法

    python 复制代码
    from django.db.models import F
    F('列名') # 注意时列名,不是Model类属性名
  • 示例1:更新Book实例中所有的零售价涨10元

    python 复制代码
    Book.objects.all().update(market_price = F('market_price') + 10)
    '''
    转化为的SQL语句
    UPDATE `bookstore_book` SET `market_price` = (`bookstore_book`.`market_price` + 10)
    '''
    # 以上做法好于如下代码
    books = Book.objects.all()
    for book in books:
        book.market_price = book.marget_price + 10
        book.save()
  • 示例2:对数据库中的两个字段的值进行比较,列出哪些书的零售价高于定价.

    python 复制代码
    from django.db.models import F
    from boookstore.models import Book
    books = Book.objects.filter(market_price__gt=F('price'))
    '''
    SELECT * FROM `bookstore_book`
    WHERE `bookstore_book`.`market_price` > (`bookstore_book`.`price`)
    '''
    for book in books:
        print(book.title, '定价:', book.price, '现价:', book.market_price)

Q对象

  • 当在获取查询结果集使用复杂的逻辑或| 逻辑非~等操作时可以借助于Q对象进行操作.

  • 示例:想要找出定价低于20元或清华大学出版社的全部书

    python 复制代码
    from django.db.models import Q
    Book.objects.filter(Q(price__lt=20) | Q(pub='清华大学出版社'))
  • 作用: 在条件中用来实现 and(&) or(|) not(~)操作

  • 语法

    • Q(条件1)|Q(条件2) # 条件1或条件2成立
    • Q(条件1)&Q(条件2) # 条件1和条件2同时成立
    • Q(条件1)&~Q(条件2) # 条件1成立且条件2不成立
  • 示例:

    python 复制代码
    from django.db.models import Q
    
    
    # 查找清华大学出版社的书或价格低于50的书
    Book.objects.filter(Q(pub_house='清华大学出版社')|Q(market_price__lt=50))
    
    
    #查找不是机械工业出版社且价格低于50的书
    Book.objects.filter(Q(market_price__lt=50) & ~Q(pub_house='机械工业出版社'))

聚合查询aggregate

聚合查询是指对一个数据表中的一个字段的数据进行部分或全部统计查询.

整表聚合

  • 不带分组的聚合查询是将全部的数据进行集中统计查询

  • 导入方法:from django.db.models import *

  • 聚合函数: Sum, Avg, Count, Max, Min

  • 语法:

    • MyModel.objects.aggregate(结果变量名=聚合函数('列')
    • 返回值:{"结果变量名":值}
  • 示例

    python 复制代码
    from django.db.models import Count
    
    
    Book.objects.aggregate(res=Count('id))
    # 返回: {'res':4}

分组聚合annotate

  • 通过计算查询结果中每一个对象所关联的一类对象集合,从而得出总计值(也可以是平均值或总和),即为查询集的每一项生成聚合.

  • 语法

    • QuerySet.annotate(结果变量名=聚合函数('列'))
    • 返回值:QuerySet
  • 返回的QuerySet还可以调用QuerySet所具有的方法

    • pub_set.annotate(myCount=Count('pub')).filter(myCount__gt=2)
  • 示例

    python 复制代码
    pub_set = Book.objects.values('pub')
    print(pub_set)
    '''
    <QuerySet [
        {'pub':'清华大学出版社'},
        {'pub':'清华大学出版社'},
        {'pub':'机械工业出版社'},
        {'pub':'清华大学出版社'}
    ]>
    '''
    pub_count_set = pub_set.annotate(myCount=Count('pub'))
    print(pub_count_set)
    '''
    <QuerySet [
        {'pub':'清华大学出版社', 'myCount':3},
        {'pub':'机械工业出版社', 'myCount':1}
    ]>
    '''

原生数据库操作 #能用ORM还是用ORM

MyModel.objects.raw()

  • 仅支持查询操作

  • 语法: MyModel.objects.raw('sql语句',拼接参数)

  • 返回值:RawQuerySet集合对象 (#区别于QuerySet对象,只支持基本操作如循环,不支持在filter)

  • 示例:

    python 复制代码
    books = models.Book.objects.raw('select * from bookstore_book')
    for book in books:
        print(book)
  • 使用原生语句时小心SQL注入

    • 错误:s1 = Book.objects.raw('select * from bookstore_book where id=%s' %('1 or 1=1')) //拼接出来为 id =3 or 1=1
    • 正确:s1 = Book.objects.raw('select * from bookstore_book where id=%s', ['1 or 1=1']) //拼接出来为 id = '3 or 1=1' 多了个单引号

connection.cursor().execute

  • 创建cursor类的cur对象,为了异常时可以释放cursor资源,通常使用with语句
  • 返回成功执行的SQL语句的数据的条数
  • 语法

from django.db import connection

with connection.cursor() as cur:

cur.execute('执行SQL语句', '拼接参数')

  • 示例:

    python 复制代码
    # 用SQL语句将id为10的书的出版社更改为"XXX出版社"
    from django.db import connection
    
    
    with connection.cursor() as cur:
        cur.execute('update bookstore_book set pub_house="XXX出版社" where id=10;')
    
    
    with connection.cursor() as cur:
        # 删除id为1的一条记录   
        cur.execute('delete from bookstore_book where id=1;')  
相关推荐
luofeiju8 分钟前
数字图像处理与OpenCV初探
c++·图像处理·python·opencv·计算机视觉
壹米饭12 分钟前
Java程序员学Python学习笔记一:学习python的动机与思考
java·后端·python
全栈派森20 分钟前
机器学习第五课: 深度神经网络
后端·神经网络·机器学习
电院工程师33 分钟前
SM3算法Python实现(无第三方库)
开发语言·python·算法·安全·密码学
白露与泡影43 分钟前
springboot + nacos + k8s 优雅停机
spring boot·后端·kubernetes
菜鸟谢1 小时前
windows xp 下载 sp0 sp1 sp2 sp3 sp4
后端
CodeDevMaster1 小时前
在Jupyter Notebook中使用Conda虚拟环境
python·jupyter
AirMan1 小时前
你真的懂 MySQL 的一致性读和当前读的区别吗?
后端·面试
David爱编程1 小时前
容器性能优化实战指南——防止“吃爆”服务器就靠这些招!
后端·docker·容器
Android洋芋1 小时前
GitHub项目部署的终极指南:从零到一掌握Docker实战
后端