Django-orm操作--补充

 

一、配置

首先我的项目结构是:

项目名: book有两个appbookmanage、booktestone

 

 

 

1.1 项目准备

 

1.创建项目

  • django-admin startproject book

     

  • 2.创建应用

    python manager.py startapp bookmanage

     

  • 3.更换python解释器:按需选择
  • 4、项目book中配置settings.py
    •   
      #子应用注册
      INSTALLED_APPS = [
          'django.contrib.admin',
          'django.contrib.auth',
          'django.contrib.contenttypes',
          'django.contrib.sessions',
          'django.contrib.messages',
          'django.contrib.staticfiles',
          'bookmanage',  # 注册子应用
          'booktestone.apps.BooktestoneConfig', # 注册子应用
      
      ]
      
      
      
      # 日志打印
      LOGGING = {
          'version': 1,
          'disable_existing_loggers': False,
          'handlers': {
              'console': {
                  'level': 'DEBUG',
                  'class': 'logging.StreamHandler',
              },
          },
          'loggers': {
              'django.db.backends': {
                  'handlers': ['console'],
                  'propagate': True,
                  'level': 'DEBUG',
              },
          }
      }
      
      #设置中文
      LANGUAGE_CODE = 'zh-Hans'
      #亚洲上海时区
      TIME_ZONE = 'Asia/Shanghai'
      book/settings.y

       

  • 5、模板路径
    •   在应用同级目录下,创建templates模板文件夹
    • TEMPLATES = [
          {
              'BACKEND': 'django.template.backends.django.DjangoTemplates',
              'DIRS': [os.path.join(BASE_DIR, 'templates')],  # 配置模板位置
              'APP_DIRS': True,
              'OPTIONS': {
                  'context_processors': [
                      'django.template.context_processors.debug',
                      'django.template.context_processors.request',
                      'django.contrib.auth.context_processors.auth',
                      'django.contrib.messages.context_processors.messages',
                  ],
              },
          },
      ]
      book/settings.py

       

  • 6、项目中匹配urls, 使用include将路由分发到对应的app中
    •   
      from django.contrib import admin
      from django.urls import path,include
      
      urlpatterns = [
          path('admin/', admin.site.urls),
          path('bookmanage/', include('bookmanage.urls')), #分发路由
          path('bookmanagetestone/', include('booktestone.urls')),
      ]
      book/urls.py

       

  • 7、应用中匹配urls.py
    •   
      from django.contrib import admin
      from django.urls import path,include
      from .views import  index,save, cre_info,up_info,get_info,get_all_info,delete_info,get_f_info,get_Q_info
      
      urlpatterns = [
          path('index', index),
          path('get_info',get_info ),
          path('get_all_info', get_all_info),
          path('get_f_info',get_f_info),
          path('get_q_info',get_Q_info),
          path('save',save),
          path('create', cre_info),
          path('update', up_info),
          path('delete_info', delete_info),
      ]
      bookmanage/urls.py

       

  • 根据人物表结构设计模型类:
    • 模型类

1.2、mysql项目配置 

1、使用MySQL数据库首先需要安装驱动程序

  

pip install PyMySQL

 

2、在settings.py中保存了数据库的连接配置信息,Django默认初始配置使用sqlite数据库。:

  • # 添加mysql配置
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql', # mysql引擎
            'HOST': '192.168.21.196', # 主机
            'PROT': '3306', #端口
            'USER':'root', # 用户名
            'PASSWORD':'Password@123', # 密码
            'NAME':'book',  #指定数据库
        }
    }

        * 然后去mysql数据库中创建book表

   

create database book charset=utf8;

 

 3、在Django的工程同名子目录的__init__.py文件中添加如下语句

eg:我的项目是book,在book/__init__.py中添加

 

import  pymysql
pymysql.install_as_MySQLdb()

作用是让Django的ORM能以mysqldb的方式来调用PyMySQL。

 

 

 二、定义模型

 2.1、定义模型类

  • 模型类被定义在"应用/models.py"文件中。
  • 模型类必须继承自Model类,位于包django.db.models中。

接下来首先以"图书-人物"管理为例进行演示。

2.1.1、定义

在子应用bookmanage/models.py中定义

from django.db import models

# Create your models here.
#准备书籍列表信息得模型
class BookInfo(models.Model):
    # 创建字段
    name = models.CharField(max_length=10)
    pub_date = models.DateField(verbose_name='发布日期', null=True)
    readcount = models.IntegerField(default=0, verbose_name='阅读量')
    commentcount = models.IntegerField(default=0, verbose_name='评论量')
    is_delete = models.BooleanField(default=False, verbose_name='逻辑删除')
    class Meta:
        db_table = 'bookinfo' # 指明数据库表名,因为不加这个表名就是app.表名的展示,加上这个就是去除app.的开头
        verbose_name = '图书信息' # 在站点中显示的名称
    def __str__(self):  # 站点后台显示的可显示的字段中文
        """定义每个数据对象的显示信息"""
        return self.name


# 准备人物列表信息的模型类
class PeopleInfo(models.Model):
    GENDER_CHOICES = (
        (0, 'male'),
        (1, 'female')
    )
    name = models.CharField(max_length=20, verbose_name='名称')
    gender = models.SmallIntegerField(choices=GENDER_CHOICES, default=0, verbose_name='性别')  # SmallIntegerField 枚举类型
    description = models.CharField(max_length=200, null=True, verbose_name='描述信息')
    book = models.ForeignKey(BookInfo, on_delete=models.CASCADE, verbose_name='图书')  # 外键  # models.CASCADE 外键要加上级联删除
    is_delete = models.BooleanField(default=False, verbose_name='逻辑删除')

    class Meta:
        db_table = 'peopleinfo'
        verbose_name = '人物信息'

    def __str__(self):
        return self.name

 

2.1.3 数据库表名

模型类如果未指明表名,Django默认以小写app应用名_小写模型类名为数据库表名。

可通过db_table指明数据库表名。

 

2.1.4、

1) 数据库表名

模型类如果未指明表名,Django默认以小写app应用名_小写模型类名为数据库表名。

可通过db_table指明数据库表名。

 

2.1.5、属性命名限制

  • 不能是python的保留关键字。
  • 不允许使用连续的下划线,这是由django的查询方式决定的。
  • 定义属性时需要指定字段类型,通过字段类型的参数指定选项,语法如下:

  • 属性=models.字段类型(选项)

 

2.1.6、字段类型

 

 

类型说明
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,对上传的内容进行校验,确保是有效的图片

 

 

2.1.7、 选项

选项说明
null 如果为True,表示允许为空,默认值是False
blank 如果为True,则该字段允许为空白,默认值是False
db_column 字段的名称,如果未指定,则使用属性的名称
db_index 若值为True, 则在表中会为此字段创建索引,默认值是False
default 默认
primary_key 若为True,则该字段会成为模型的主键字段,默认值是False,一般作为AutoField的选项使用
unique 如果为True, 这个字段在表中必须有唯一值,默认值是False

 

 null是数据库范畴的概念,blank是表单验证范畴的

2.1.8、外键

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

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

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

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

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

  • SET()设置为特定值或者调用特定方法

  • DO_NOTHING不做任何操作,如果数据库前置指明级联性,此选项会抛出IntegrityError异常

 

2.2 迁移

将模型类同步到数据库中。

2.2.1 、生成迁移文件

python manage.py makemigrations

2.2.2、 同步到数据库中

python manage.py migrate

 

2.3 添加测试数据

insert into bookinfo(name, pub_date, readcount,commentcount, 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);
bookinfo
insert into peopleinfo(name, gender, book_id, description, 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);
peopleinfo

 

三、ORM单表操作

3.1 基础条件查询

3.1.1 基本查询

get查询单一结果,如果不存在会抛出模型类.DoesNotExist异常。

all查询多个结果

count查询结果数量。

###############################基本查询#####################################


# get  得到某一个数据
# all  获取所有的
# count 个数

#select * from bookinfo where id=1
# 返回一个对象
book=BookInfo.objects.get(id=1)

#查询id 不存在的数据会抛出异常
book=BookInfo.objects.get(id=100)
"""
book.models.DoesNotExist: BookInfo matching query does not exist.
"""
try:
    book=BookInfo.objects.get(id=2)
# except Exception :
#     pass
except BookInfo.DoesNotExist:
    pass

# 返回所有结果,列表
BookInfo.objects.all()

# count
BookInfo.objects.all().count()
BookInfo.objects.count()

 

3.1.2 过滤查询

实现SQL中的where功能,包括

  • filter过滤出多个结果
  • exclude排除掉符合条件剩下的结果
  • get过滤单一结果

对于过滤条件的使用,上述三个方法相同,故仅以filter进行讲解。

过滤条件的表达语法如下:

属性名称__比较运算符=# 属性名称和比较运算符间使用两个下划线,所以属性名不能包括多个下划线
select  from bookinfo where 条件语句
相当于 where查询

filter          : 筛选/过滤 返回 n个结果 (n = 0/1/n)
get             :           返回1个结果
exclude         : 排除掉符合条件剩下的结果  相当于 not

语法形式:
    以filter(字段名__运算符=值) 为例

例如:

查询编号为1的图书
查询书名包含''的图书
查询书名以''结尾的图书
查询书名为空的图书
查询编号为1或3或5的图书
查询编号大于3的图书
查询1980年发表的图书
查询1990年1月1日后发表的图书

 

# 查询编号为1的图书
# exact 精确的 准确的 就是等于
BookInfo.objects.get(id__exact=1)
BookInfo.objects.get(id=1)

BookInfo.objects.filter(id=1)
BookInfo.objects.filter(id__exact=1)
# 查询书名包含'湖'的图书
# contains 包含
BookInfo.objects.filter(name__contains='')
# 查询书名以'部'结尾的图书
BookInfo.objects.filter(name__endswith='')
# 查询书名为空的图书
BookInfo.objects.filter(name__isnull=True)  # 必须使用where来进行过滤,判断为空不可以使用get
# 查询编号为1或3或5的图书
BookInfo.objects.filter(id__in=[1,3,5])
    # 查询编号大于3的图书
    # gt 大于         great 大
    # gte  大于等于    e equal 等于
    # lt  小于        less than
    # lte 小于等于
    book = BookInfo.objects.filter(id__gt = 3) # gt大于
    print(book)
    book = BookInfo.objects.filter(id__gte=3)  # gte等于
    print(book)
    book = BookInfo.objects.filter(id__lt=3) # lt小于
    print(book)
    book = BookInfo.objects.filter(id__lte=3) # lte小于等于
    print(book)

# 查询书籍id不为3的图书
BookInfo.objects.exclude(id__exact=3)
BookInfo.objects.exclude(id=3)

# 查询1980年发表的图书
BookInfo.objects.filter(pub_date__year='1980')

# 查询1990年1月1日后发表的图书
BookInfo.objects.filter(pub_date__gt='1990-1-1')

# BookInfo.objects.filter(pub_date__gt='1990.1.1') #错误的

 

3.1.2.1、相等

exact:表示判等。

例:查询编号为1的图书。

BookInfo.objects.filter(id__exact=1)
可简写为:
BookInfo.objects.filter(id=1)

 

3.1.2.2、模糊查询

contains:是否包含。

说明:如果要包含%无需转义,直接写即可。

例:查询书名包含'传'的图书。

BookInfo.objects.filter(name__contains='')
<QuerySet [<BookInfo: 射雕英雄传>]>

startswith、endswith:以指定值开头或结尾。

例:查询书名以'部'结尾的图书

>>> BookInfo.objects.filter(name__endswith='')
<QuerySet [<BookInfo: 天龙八部>]>

以上运算符都区分大小写,在这些运算符前加上i表示不区分大小写,如iexact、icontains、istartswith、iendswith.

3.1.2.3、 空查询

isnull:是否为null。

例:查询书名为空的图书。

>>> BookInfo.objects.filter(name__isnull=True)
<QuerySet []>

 

3.1.2.4、范围查询

in:是否包含在范围内。

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

>>> BookInfo.objects.filter(id__in=[1,3,5])
<QuerySet [<BookInfo: 射雕英雄传>, <BookInfo: 笑傲江湖>]>

 

3.1.2.5、比较查询

  • gt大于 (greater then)
  • gte大于等于 (greater then equal)
  • lt小于 (less then)
  • lte小于等于 (less then equal)

例:查询编号大于3的图书

    # 查询编号大于3的图书
    # gt 大于         great 大
    # gte  大于等于    e equal 等于
    # lt  小于        less than
    # lte 小于等于
    book = BookInfo.objects.filter(id__gt = 3) # gt大于
    print(book)
    book = BookInfo.objects.filter(id__gte=3)  # gte等于
    print(book)
    book = BookInfo.objects.filter(id__lt=3) # lt小于
    print(book)
    book = BookInfo.objects.filter(id__lte=3) # lte小于等于
    print(book)
    # 查询书籍id不为3的图书
    book =BookInfo.objects.exclude(id__exact=3)
    book = BookInfo.objects.exclude(id=3)

不等于的运算符,使用exclude()过滤器。

例:查询编号不等于3的图书

>>> BookInfo.objects.filter(id__gt=3)
<QuerySet [<BookInfo: 雪山飞狐>]>

 

3.1.2.6、日期查询

year、month、day、week_day、hour、minute、second:对日期时间类型的属性进行运算。

例:查询1980年发表的图书。

BookInfo.objects.filter(pub_date__year=1980)  #<QuerySet [<BookInfo: 射雕英雄传>]>

例:查询1990年1月1日后发表的图书。

BookInfo.objects.filter(pub_date__gt='1990-1-1')# <QuerySet [<BookInfo: 笑傲江湖>]>
 

3.2  F和Q对象

一句话总结F和Q对象,就是一个是查询一个是比较

F对象(就是用来比较来个字段的值)

之前的查询都是对象的属性与常量值比较,两个属性怎么比较呢? 答:使用F对象,被定义在django.db.models中。

语法如下:

F(属性名)

例:查询阅读量大于等于评论量的图书。

>>> from django.db.models import F
>>> BookInfo.objects.filter(readcount__gt=F('commentcount'))# <QuerySet [<BookInfo: 雪山飞狐>]>

 

可以在F对象上使用算数运算。

例:查询阅读量大于2倍评论量的图书。

>>> BookInfo.objects.filter(readcount__gt=F('commentcount')*2)#<QuerySet [<BookInfo: 雪山飞狐>]>

 

#两个属性怎么比较 F对象
"""
F对象的语法形式

filter(字段名__运算符=F('字段名'))


"""
from django.db.models import F
#查询阅读量大于等于评论量的图书
BookInfo.objects.filter(readcount__gte=F('commentcount'))


#查询阅读量大于等于评论量2倍的图书
BookInfo.objects.filter(readcount__gte=F('commentcount')*2)


###############################Q对象(了解)#####################################

# 需要查询id大于2 并且阅读量大于20的书籍
#方式1
# filter().filter()
BookInfo.objects.filter(id__gt=2).filter(readcount__gt=20)

#方式2
# filter(条件,条件)
BookInfo.objects.filter(id__gt=2,readcount__gt=20)

# 需要查询id大于2 或者 阅读量大于20的书籍

 

 

Q对象(查询)

多个过滤器逐个调用表示逻辑与关系,同sql语句中where部分的and关键字。

例:查询阅读量大于20,并且编号小于3的图书。

>>> BookInfo.objects.filter(readcount__gt=20,id__lt=3)
<QuerySet [<BookInfo: 天龙八部>]>

或者

>>> BookInfo.objects.filter(readcount__gt=20).filter(id__lt=3)
<QuerySet [<BookInfo: 天龙八部>]>

如果需要实现逻辑或or的查询,需要使用Q()对象结合|运算符,Q对象被义在django.db.models中。

语法如下:

Q(属性名__运算符=值)

例:查询阅读量大于20的图书,改写为Q对象如下。

BookInfo.objects.filter(Q(readcount__gt=20))

 

Q对象可以使用&、|连接,&表示逻辑与,|表示逻辑或。

例:查询阅读量大于20,或编号小于3的图书,只能使用Q对象实现

>>> BookInfo.objects.filter(Q(readcount__gt=20)|Q(id__lt=3))
<QuerySet [<BookInfo: 射雕英雄传>, <BookInfo: 天龙八部>, <BookInfo: 雪山飞狐>]>

 

Q对象前可以使用~操作符,表示非not。

例:查询编号不等于3的图书。

>>> BookInfo.objects.filter(~Q(id=3))
<QuerySet [<BookInfo: 射雕英雄传>, <BookInfo: 天龙八部>, <BookInfo: 雪山飞狐>]>
from django.db.models import Q

"""
Q(字段名__运算符=值)

或  Q()|Q() ..
并且 Q()&Q() ..
not  ~Q()
"""
BookInfo.objects.filter(Q(id__gt=2)|Q(readcount__gt=20))

# 查询书籍id不为3
BookInfo.objects.exclude(id=3)

BookInfo.objects.filter(~Q(id=3))

 

 

3.3 聚合函数和排序函数

要想使用聚合函数首先要导入对应的包

    from django.db.models import Sum,Avg,Max,Min,Count

 

3.3.1 聚合函数

使用aggregate()过滤器调用聚合函数。聚合函数包括:Avg平均,Count数量,Max最大,Min最小,Sum求和,被定义在django.db.models中。

例:查询图书的总阅读量。

>>> from django.db.models import Sum
>>> BookInfo.objects.aggregate(Sum('readcount'))
{'readcount__sum': 126}

注意aggregate的返回值是一个字典类型,格式如下:

{'属性名__聚合类小写':值}

  如:{'readcount__sum': 126}

使用count时一般不使用aggregate()过滤器。

例:查询图书总数。

BookInfo.objects.count()

注意count函数的返回值是一个数字。

3.3.2. 排序

使用order_by对结果进行排序

# 默认升序
>>> BookInfo.objects.all().order_by('readcount')
<QuerySet [<BookInfo: 射雕英雄传>, <BookInfo: 笑傲江湖>, <BookInfo: 天龙八部>, <BookInfo: 雪山飞狐>]>


# 降序
>>> BookInfo.objects.all().order_by('-readcount')
<QuerySet [<BookInfo: 雪山飞狐>, <BookInfo: 天龙八部>, <BookInfo: 笑傲江湖>, <BookInfo: 射雕英雄传>]>

 

 

四、关联查询

 关联查询有一对多 ,多对一,多对多的查法

4.1、一到多

 

语法形式

    通过书籍查询人物信息( 已知 主表数据,关联查询从表数据)

    主表模型(实例对象).关联模型类名小写_set.all()



    通过人物查询书籍信息( 已知 从表数据,关联查询主表数据)

    从表模型(实例对象).外键

 

4.1.1、正向查询

由多到一的访问语法:

多对应的模型类对象.多对应的模型类中的关系类属性名 例:

  # 查询人物为1的书籍信息
    '''
    因为关联字段在人物表中,通过people表去book表中查询是正向查询用
    多对应的模型类对象.多对应的模型类中的关系类属性名 例:people表的对应.book 查询
    '''
    people = PeopleInfo.objects.get(id=1)
    people.book.name

访问一对应的模型类关联对象的id语法:

多对应的模型类对象.关联类属性_id

>>> person = PeopleInfo.objects.get(id=1)
>>> person.book_id

 

 

4.1.2、反向查询

由一到多的访问语法:

一对多的模型类对象.多对应的模型类名小写_set 例:

 

    # 查询书籍为1的所有人物信息

    '''
    因为关联字段在人物表中,通过book表去people中查询是反向查询用
    模型类对象.多对应的模型类名小写_set 例:book.peopleinfo_set.all()查询
    '''
    book = BookInfo.objects.get(id=1) # 查询到书籍id为1的信息
    propleinfo = book.peopleinfo_set.all() # 反向查询获取对应的人物信息

 

 

 

4.2 关联查询的筛选

书籍和人物的关系是   1:n
书籍 中没有任何关于人物的字段 (不要考虑隐藏的哪个字段)

人物 中有关于书籍的字段 book 外键

语法形式

    我们需要的是 书籍信息,已知条件是 人物信息
    我们需要的是 主表数据,已知条件是 从表信息

    filter(关联模型类名小写__字段__运算符=值)


    我们需要的是 人物信息,已知条件是 书籍信息
    我们需要是是 从表数据,已知条件是 主表信息

    filter(外键__字段__运算符=值)

 

查询图书,要求图书人物为"郭靖"
查询图书,要求图书中人物的描述包含"八"

反向查询:

主表的表名__字段信息

"""
查询图书,要求图书人物为"郭靖"
查询图书,要求图书中人物的描述包含"八"
"""

#需要的是图书,条件是人物
BookInfo.objects.filter(peopleinfo__name__exact='郭靖')
BookInfo.objects.filter(peopleinfo__name='郭靖')

 

正向查询:

直接关联的字段. 要查询的字段

"""
查询书名为“天龙八部”的所有人物
查询图书阅读量大于50的所有人物
"""
PeopleInfo.objects.filter(book__name='天龙八部')
PeopleInfo.objects.filter(book__name__exact='天龙八部')

PeopleInfo.objects.filter(book__readcount__gt=50)

 

 

 

 

 

.

 

posted @ 2022-08-12 17:24  可爱的红领巾  阅读(68)  评论(0编辑  收藏  举报