Django模型使用(进阶版)


orm支持使用不同的数据库,可以通过方便的配置,切换使用不同的数据库。

django项目默认使用的是sqlite3小型数据库, 我们可以如下操作,把它修改为使用mysql数据库:

Django配置使用mysql数据库:
  1. 修改settings.py中的DATABASES。

    # Project01/setting.py
    DATABASES = {
        'default': {
            # 'ENGINE': 'django.db.backends.sqlite3',
            # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    
            # 配置mysql数据库
            'ENGINE': 'django.db.backends.mysql',
            'NAME': "db_django01",
            'USER': "root",
            'PASSWORD': "root",
            'HOST': "localhost",
            'PORT': 3306,
        }
    }
    1. 在python虚拟环境下安装mysqlPython包:

      python2:

      pip install mysql-python
      

      python3:

      pip install pymysql
      
    2. 在app01/__init__.py中加如下内容:

      import pymysql
      pymysql.install_as_MySQLdb()
      
    3. 重新生成数据库表

      1) 删除掉app01/migrations目录下所有的迁移文件
      2) 重新执行:

      python manage.py makemigrations
      python manage.py migrate
      
    4. 确认是否已经生成了对应的数据库表。

字段类型和选项

在模型类中,定义属性,生成对应的数据库表字段:

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

属性名命名限制:

  • 不能是python的保留关键字。
  • 不允许使用连续的下划线,这是由django的查询方式决定的。

字段类型

使用时需要引入django.db.models包,字段类型如下:

  • AutoField:

    自动增长的IntegerField,通常不需要指定,Django会自动创建属性名为id的自动增长属性。

  • BooleanField:

    布尔字段,值为True或False

  • NullBooleanField:

    支持Null、True、False三种值。

  • CharField (max_length=字符个数):

    字符串 必须指定的参数: max_length 最大字符个数

  • TextField:

    大文本字段,一般超过4000个字符时使用。

  • DateField:[auto_now=False, auto_now_add=False]:

    日期

    参数auto_now表示每次保存对象时,自动设置该字段为当前时间,用于"最后一次修改"的时间戳,它总是使用当前日期,默认为false。

    参数auto_now_add表示当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为false。

    参数auto_now_add和auto_now是互斥的,不能在同时使用到一个类属性中。

  • TimeField:

    时间,参数同DateField。

  • DateTimeField:

    日期时间,参数同DateField。

  • IntegerField:

    整数。在Django所支持的所有数据库中, 从 -2147483648 到 2147483647 范围内的值是合法的

  • DecimalField (max_digits=None, decimal_places=None):

    十进制浮点数,用python中的Decimal实例来表示,适合用来保存金额。
    必须指定参数: max_digits总位数,decimal_places小数位数。
    例:最大值:99.99 -- DecimalField (max_digits=4, decimal_places=2)

  • FloatField:

    浮点数,用python中的float来表示,有误差。

  • FileField:

    上传文件字段。

  • ImageField:

    继承于FileField,对上传的内容进行校验,确保是有效的图片。

注意: 只要修改了表字段的类型,就需要重新生成迁移文件并执行迁移操作。


字段选项

通过选项实现对数据库表字段的约束:

选项默认值描述是否要重新迁移修改表结构
nullFalse如果为True,数据库中字段允许为空
uniqueFalseTrue表示这个字段在表中必须有唯一值
db_column属性名称字段名,如果未指定,则使用属性的名称
db_indexFalse若值为True, 则在表中会为此字段创建索引。 查看索引:show index from 表名
primary_keyFalse若为True,则该字段会成为模型的主键字段,一般作为AutoField的选项使用
default 默认值
blankFalseTrue,html页面表单验证时字段允许为空

查询

  • 每个模型类默认都有一个叫 objects 的类属性,它由django自动生成,类型为: django.db.models.manager.Manager,可以把它叫 模型管理器

    >>> Employee.objects
    <django.db.models.manager.Manager object at 0x7fcfcdf67550>
    
  • objects模型管理器中提供了一些查询数据的方法:

    objects管理器中的方法返回类型作用
    模型类.objects.get()模型对象返回一个对象,且只能有一个
    如果查到多条数据,则报:MultipleObjectsReturned 
    如果查询不到数据,则报:DoesNotExist
    模型类.objects.filter()QuerySet返回满足条件的对象
    模型类.objects.all()QuerySet返回所有的对象
    模型类.objects.exclude()QuerySet返回不满条件的对象
    模型类.objects.order_by()QuerySet对查询结果集进行排序
    模型类.objects.aggregate()字典,例如:
    {'salary__avg': 9500.0}
    进行聚合操作
    Sum, Count, Max, Min, Avg
    模型类.objects.count()数字返回查询集中对象的数目

对模型类作修改:

  • 员工表新增了hire_date入职时间字段
  • 员工表的comment备注信息字段可以为空
  • 代码参考如下:

    class Department(models.Model):
        """部门类"""
    
        # 部门名称:字符串类型(必须要指定最大长度)
        name = models.CharField(max_length=20)
        # 部门成立时间: 日期类型
        create_date = models.DateField(auto_now_add=True)
        # modify_date = models.DateField(auto_now=True, null=True)
    
        def __str__(self):
            return self.name
    
    
    class Employee(models.Model):
        """员工类"""
        name = models.CharField(max_length=20)
        age = models.IntegerField()
        sex = models.IntegerField()
        # 工资:浮点类型(必须要指定两个选项)  999999.99
        salary = models.DecimalField(max_digits=8, decimal_places=2)
        # 备注信息: 可以为空
        comment = models.CharField(max_length=300, null=True, blank=True)
        # 员工入职时间
        hire_date = models.DateField()
        # 一对多的外键:员工所属部门 department_id
        department = models.ForeignKey('Department')
    
        def __str__(self):
            return self.name

filter方法

filter方法用来实现条件查询,返回QuerySet对象,包含了所有满足条件的数据。 通过方法参数,指定查询条件:

模型类.objects.filter(模型类属性名__条件名 = 值)

  • 判等: exact

    例:查询id1的员工

    判等: exact

    例:查询id为1的员工 (SQL: where id = 1)

    Employee.objects.filter(id=1)
    Employee.objects.filter(id__exact=1)
  • 模糊查询: contains / endswith / startswith

  • 例:查询名字包含'马'的员工 (SQL: where name like '%马%')

    Employee.objects.filter(name__contains='马')
    

    例:查询名字以'军'结尾的员工 (SQL: where name like '%军')

    Employee.objects.filter(name__endswith='军')
  • 空查询: isnull

    例:查询备注信息不为空的员工(SQL: where comment is not null)

    Employee.objects.filter(comment__isnull=False)
  • 范围查询: in

    例:查询id编号为1或3或5的员工 (SQL: where id in (1,3,5))

    Employee.objects.filter(id__in = [1,3,5])

. 比较查询: gt(greater than)、lt(less than)、gte、lte

     例:查询age大于30的员工 (SQL: where age >= 30)

        Employee.objects.filter(age__gte = 30)

   .     日期查询: year

    - mysql: 
    - date函数: date('2017-1-1')   
    - year函数:  year(hire_date)  
    - python: 
    - date函数: date(2017,1,1)

        例:查询2015年入职的员工 (SQL: where year(hire_date) = 2015)

    Employee.objects.filter(hire_date__year=2015)

        例:查询2014年1月1日后入职的员工 (SQL: where hire_date >= date('2014-1-1'))

    from datetime import date
    Employee.objects.filter(hire_date__gt=date(2014,1,1))  

exclude方法

返回不满足条件的数据: 
用法: 模型类.objects.exclude(条件)

例:查询id不为3的员工

exclude方法:返回不满足条件的数据

例:查询id不为3的员工 (SQL: where id != 3)

Employee.objects.exclude(id=3)

F对象

  • 作用: 引用某个表字段的值, 生成对应的SQL语句

    应用场景:比较表中的两个字段

    例:查询语文分数大于数学分数的学生
    成绩表.objects.filter(语文__gt=F('数学'))
    
  • 用法: F('字段')

    使用之前需要先导入:

    from django.db.models import F
  • 示例:

    # 例:查询年龄大于id的员工信息(无实际意义)
    Employee.objects.filter(age__gt = F('id'))
    
    # 例:查询年龄大于4倍id编号的员工信息(无实际意义)
    Employee.objects.filter(age__gt = F('id')*4)


Q对象

  • 作用: 组合多个查询条件,可以通过&|~(not and or)对多个Q对象进行逻辑操作。

  • 用法: Q(条件1) 逻辑操作符 Q(条件2)

    需要先导入:

    from django.db.models import Q
    
  • 示例:

    例:查询id大于3且年龄大于30的员工信息。

    Employee.objects.filter(id__gt=3, age__gt=30)
    Employee.objects.filter(Q(id__gt=3) & Q(age__gt=30))
    

    例:查询id大于3或者年龄大于30的员工信息。

    Employee.objects.filter(Q(id__gt=3) | Q(age__gt=30))
    

    例:查询id不等于3员工信息。

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

order_by方法

  • 作用: 对查询结果进行排序, 默认升序

  • 用法:

    升序: 模型类.objects.order_by('字段名') 
    降序: 模型类.objects.order_by('-字段名')

  • 示例:

    例:查询所有员工信息,按照id从小到大进行排序。

    Employee.objects.all().order_by('id')
    Employee.objects.order_by('id')
    

    例:查询所有员工信息,按照id从大到小进行排序。

    Employee.objects.all().order_by('-id')
    

    例:把id大于3的员工信息按年龄从大到小排序显示;

    Employee.objects.filter(id__gt=3).order_by('-age')

aggregate方法

  • 作用: 聚合操作,对多行查询结果中的一列进行操作,返回一个值。

  • 用法: 模型类.objects.aggregate(聚合类('模型属性'))

    • 常用聚合类有:Sum, Count, Max, Min, Avg等
    • 返回值是一个字典, 格式: {'属性名__聚合函数': 值}
    • 需先导入聚合类:

      from django.db.models import Sum, Count, Max, Min, Avg
  • 示例:

    • 例:查询所有员工的人数。

      Employee.objects.aggregate(Count('id'))
      

      返回结果: {'id__count': 12}

    • 例:查询所有员工的平均工资。

      Employee.objects.aggregate(Avg('salary'))
      

      返回结果: {'salary__avg': 9500.0}

count方法

  • 作用:统计满足条件的对象的个数,返回值是一个数字
  • 用法: 模型类.objects.count()
  • 示例:

    例:统计所有员工的人数。

    Employee.objects.count()
    

    例:统计id大于3的所有员工的人数。

    Employee.objects.filter(id__gt=3).count()

查看ORM语句

可以通过查看mysql的日志文件,了解Django ORM 生成出来的sql语句。

配置查看mysql日志文件:

    1、打开mysqld.cnf文件,打开68 69两行的注释:

    sudo vi /etc/mysql/mysql.conf.d/mysqld.cnf


     2、重启mysql服务

sudo service mysql restart

  3、查看mysql日志文件的内容

        sudo tail -f /var/log/mysql/mysql.log

            tail命令: 默认会显示文件的末尾,会自动刷新显示文件最新内容。退出可按ctrl+c


QuerySet查询集

  • 调用模型管理器的allfilterexcludeorder_by方法会产生一个QuerySet,可以在QuerySet上继续调用这些方法,比如:

    Employee.objects.filter(id__gt=3).order_by('-age')
    
  • QuerySet可以作取下标操作, 注意:下标不允许为负数:

    b[0]

    • 取出QuerySet的第一条数据,
    • 不存在会抛出IndexError异常
  • QuerySet可以作切片 操作, 切片操作会产生一个新的QuerySet,注意:下标不允许为负数

  • QuerySet的get()方法

    • 取出QuerySet的唯一一条数据
    • QuerySet不存在数据,会抛出: DoesNotExist异常
    • QuerySet存在多条数据,会抛出:MultiObjectsReturned异常
  • QuerySet的exists方法: QuerySet有一个exists方法,可以判断是否有数据。

  • QuerySet的特性:

    • 惰性查询:只有在使用QuerySet中的数据时, 才会去查询数据库中的数据。
    • 缓存:第一次遍历使用了QuerySet中的所有的对象(比如通过 列表生成式 遍历了所有对象),则django会把数据缓存起来, 第2次再使用同一个QuerySet时,将会使用缓存。注意:使用索引或切片引用查询集数据,将不会缓存,每次都会查询数据库。

增删改

  • 调用一个模型类对象的save方法, 就可以实现数据新增或修改,id在表中存在为修改,否则为新增。
  • 调用一个模型类对象的delete方法,就可以实现数据删除,会根据id删除。
  • 改: 模型类.filter(条件).update(属性1=值1,属性2=值2..)
  • 删: 模型类.filter(条件).delete()


一对多关联查询

假设在一对多关系中,一对应的类叫做一类,多对应的类叫做多类:

一、通过对象进行关联查询

  • 用法:

    由一类对象查询多类对象:

    一类对象.多类名小写_set.all()
    

    由多类对象查询一类对象:

    多类对象.关联属性
    
  • 示例:

    # 查询部门id为1的所有员工
    d = Department.objects.get(id=1)
    d.employee_set.all()    # 一查多
    
    # 查询id为1的员工所属的部门信息
    e = Employee.objects.get(id=1)
    e.department            # 多查一
    

二、通过模型类进行关联查询

  • 用法:

    通过多类的条件查询一类数据:

    一类名.objects.filter(多类名小写__多类属性名__条件名=值) 
    

    通过一类的条件查询多类数据:

    多类名.objects.filter(关联属性__一类属性名__条件名=值)
    

    提示:会生成内连接语句进行查询, 条件名为in,gtisnull

关联查询

一、通过对象进行查询:

- 查询部门id1的所有员工的信息。

        d = Department.objects.get(id=1)
        d.employee_set.all()

- 例:查询id10的员工所属的部门信息。

        e = Employee.objects.get(id=10)
        e.department

二、通过模型类进行关联查询

  • 示例:

    例1:查询部门信息,要求部门中员工的名字包含'马'

    select * from app01_department as d inner join app01_employee  as e 
    on d.id = e.department_id where e.name like '%马%';    
    
    Department.objects.filter(employee__name__contains='马')  
    

    例2:查询部门信息,要求部门中的员工的年龄大于30

    select * from app01_department as d inner join app01_employee as e 
    on d.id=e.department_id where age > 30    
    
    Department.objects.filter(employee__age__gt=30)
    

    例3:查询部门为“研发部”的所有员工

    select * from app01_employee as e inner join app01_department as d 
    on e.department_id = d.id where d.name='研发部';     
    
    Employee.objects.filter(department__name__exact='研发部')       
    Employee.objects.filter(department__name='研发部')     


自关联

自关联是一种特殊的一对多的关系:


自关联关联属性定义:

# 区域表自关联属性:特殊的一对多
关联属性 = models.ForeignKey('self')

添加区域模型类

class Area(models.Model):
    """区域类: 保存省份 城市 区县"""

    # 区域名称
    title = models.CharField(max_length=30)

    # 关联属性:自关联 (表示上级区域)
    parent = models.ForeignKey('self', null=True, blank=True)

    def __str__(self):
        return self.title

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值