django rom学习记录

掌握django orm

序 配置mysql数据库

  • 使用pycharm管理数据库

    在这里插入图片描述

    • 在设置中修改数据库信息

      DATABASES = {
          'default': {
              'ENGINE': 'django.db.backends.mysql',
              'NAME': 'imooc',
              'USER': 'root',
              'PASSWORD': '75267156',
              'HOST': '127.0.0.1',
              'PORT': '3306',
          }
      }
      
    • 安装相关插件并应用

      使用pip install pymysql命令安装

      在项目的__ init__.py中添加

      import pymysql
      pymysql.install_as_MySQLdb()
      

orm介绍

  • orm是什么
    • 将对象自动存放到关系型数据库中,充当业务逻辑层和数据层中的桥梁
      在这里插入图片描述

    • 在models.py中编写模型类

    • 模型类的优势与劣势

      • 让开发人员专注业务逻辑的开发处理,提高效率
      • 在一定程度上牺牲程序的执行效率

字段类型和参数

常用的字段

class Test(models.Model):
    # 自增长字段
    # 每增加一条时加一
    # 都是int型
    Auto = models.AutoField()
    # 下面的允许数字更大
    BigAuto = models.BigAutoField()

    # 二进制数据
    BInary = models.BinaryField()

    # 布尔型
    Boolean = models.BooleanField()
    # NullBoolean是允许为空的布尔型
    NullBoolean = models.NullBooleanField()

    # 整型
    # 正整数,并且存储字节为五个
    PositiveSmallInteger = models.PositiveSmallIntegerField()
    # 6个字节大小的整数
    SmallInteger = models.SmallIntegerField()
    # 10个字节大小的正整数
    PositiveInteger = models.PositiveIntegerField()
    # 11个字节大小
    Integer = models.IntegerField()
    # 20个大小的整型
    BigInteger = models.BigIntegerField()

    # 字符串型
    # 在数据库中对应 varchar, 需要指定程度
    Char = models.CharField()
    # 在数据库中对应 longtext, 不需要指定长度
    Text = models.TextField()

    # 时间日期型
    # 表示年月日
    Date = models.DateField()
    # 表示年月日时分秒
    DateTime = models.DateTimeField()
    # 表示一段时间, 是int型, 通过timedelta实现
    Duration = models.DurationField()

    # 浮点型
    Float = models.FloatField()
    # 他需要指定整数有多少位,小数有多少位
    Decimal = models.DecimalField()

    # 其他字段
    # 邮箱
    # 限制用户在使用表单或后台时只能输入邮箱地址格式的数据
    Email = models.EmailField()
    Image = models.ImageField()
    File = models.FileField()
    FilePath = models.FilePathField()
    URL = models.URLField()
    UUID = models.UUIDField()
    # 可以是ipv4 或 ipv6的地址
    GenericIPAddress = models.GenericIPAddressField()

关系型字段

# 关系型字段需要设置相应约束条件
class A(models.Model):
    # 一对一型
    OneToOne = models.OneToOneField(Test)


class B(models.Model):
    # 多对多型
    foreign = models.ForeignKey(A)

class C(models.Model):
    # 多对多型,默认或自定义中间件
    ManyToMany = models.ManyToManyRel(B)

字段参数

    # 1.所有字段都有的参数
    # 在默认的情况下,数据库的表明是 数据库名称_应用名称小写
    class Test(models.Model):  # courses_test

        # 字段名也是,跟属性名一致
        # 如需更改可以使用 db_column 字段实现
        PositiveSmallInteger = models.PositiveSmallIntegerField(db_column="age")
        # 使用 primary_key 参数将字段定义为主键,他默认情况下是False
        SmallInteger = models.SmallIntegerField(primary_key=True)
        # 还可以使用 verbose_name 给字段设置一个别名,相当于这个字段的别名或是备注
        Integer = models.IntegerField(verbose_name="11个字节大小")
        # 字段的唯一键 unique,这个表中字段的值必须唯一
        BigInteger = models.BigIntegerField(unique=True)
        # 使用 null,blank 允许字段为空
        # null 值数据库中为空, blank 指的是前端表单提交是是否为空
        # 不能将null设为false,而blank为true,会报错
        # 使用 db_index 为字段建立索引
        Char = models.CharField(null=True, blank=True, db_index=True)
        # 使用 help_text 在表单中为字段设置帮助信息
        Text = models.TextField(help_text="这个是longtext")
        # 使用 editable=False 让用户无法编辑,默认为true
        Date = models.DateField(editable=False)

    # 2.个别字段才有的参数
    class Test(models.Model):
        # 字符串型
        # 必须指定最大长度
        # 这里的100是指utf-8编码的字符串
        Char = models.CharField(max_length=100)

        # 时间日期型才有的参数
        # unique_for_date = true 该时间日期必须唯一
        # auto_now 是更新记录的时间
        Date = models.DateField(unique_for_date=True, auto_now=True)
        # 设置月份唯一
        # auto_now_add 表示增加记录的时间
        DateTime = models.DateTimeField(unique_for_month=True, auto_now_add=True)
        # 浮点型
        # 必须给他设定两个参数
        # max_digits 是一共多少位
        # decimal_places 是小数点后有多少位
        # 整数两位,小数点后两位
        Decimal = models.DecimalField(max_digits=4, decimal_places=2)

    # 3.关系型字段的参数
    class A(models.Model):
        # 一对一型
        # related_name 用于外键关联间的反向查询,就是通过父表查询到子表信息
        OneToOne = models.OneToOneField(Test)

    class B(models.Model):
        # 多对多型
        # on_delete 当一个被外键关联的对象被删除时,django将模仿on_delete参数定义的SQL约束执行相应操作
        # CASCADE 模拟SQL语言中的ON DELETE DASCADE约束,将定义有外键的模型对象同时删除,此为django默认操作
        foreign = models.ForeignKey(A,on_delete=models.CASCADE)
        # PROTECT 阻止上面的删除操作, 但是会弹出ProtectedError异常
        foreign = models.ForeignKey(A, on_delete=models.PROTECT)
        # SET_NULL 将外键字段设为null, 只有当子段设置了null=True,方可使用
        foreign = models.ForeignKey(A, on_delete=models.SET_NULL, null=True, blank=True)
        # SET_DEFAULT: 将外键子段设为默认值, 只有当字段设置了default参数才行
        foreign = models.ForeignKey(A, on_delete=models.SET_DEFAULT, default=0)
        # DO_NOTHING 什么也不做
        foreign = models.ForeignKey(A, on_delete=models.DO_NOTHING)
        # SET() 设置为一个传递给SET()的值或者一个回调函数的返回值,注意大小写
        foreign = models.ForeignKey(A, on_delete=models.SET )

自关联

 class AddressInfo(models.Model):
    address = models.CharField(max_length=100, null=True, blank=True, verbose_name="地址")
    # 定义自关联项
    # 可以使用 'self' 的方式自关联,也可以使用 '字段名'
    pid = models.ForeignKey('self', null=True, blank=True, verbose_name="自关联")
    # pid = models.ForeignKey('address', null=True, blank=True, verbose_name="自关联")

    # 给不同的模型类返回一个可读的字符串信息
    # def __unicode__(self)
    def __str__(self):
        # 通常可以使用上面已有的字符串,或者自己拼接
        return self.address

元数据meta

元数据介绍

class AddressInfo(models.Model):
    address = models.CharField(max_length=100, null=True, blank=True, verbose_name="地址")
    # 定义自关联项
    # 可以使用 'self' 的方式自关联,也可以使用 '字段名'
    pid = models.ForeignKey('self', null=True, blank=True, verbose_name="自关联")
    # pid = models.ForeignKey('address', null=True, blank=True, verbose_name="自关联")
    note = models.CharField(max_length=200, null=True, blank=True, verbose_name="说明信息")

    # 给不同的模型类返回一个可读的字符串信息
    # def __unicode__(self)
    def __str__(self):
        # 通常可以使用上面已有的字符串,或者自己拼接
        return self.address

    class Meta:
        # 元数据
        # 封装了一些数据库的信息
        # 定义表明
        db_table = 'address'
        # 按照指定字段进行升序排列
        ordering = ['pid']
        # 为模型类设定一个直观可读的信息
        verbose_name = '省市县地址信息'
        # 为verbose_name设定复数形式
        verbose_name_plural = verbose_name
        # 将模型类设定为基类
        # 不生成数据表,仅供其他子类继承
        abstract = True
        # 为数据表设置额外权限
        permissions = (('定义好的权限', '权限声明'),)
        # 设定是否按照django既定规则来管理模型类,如增加修改
        managed = False
        # 联合唯一键, 对应数据表中的联合唯一约束
        unique_together = ('address', 'note')  # ((),())
        # 定义模型类属于哪个应用
        app_label = 'courses'
        # 定义数据库表空间的名字
        db_tablespace = ''

模型类开发示例

在这里插入图片描述

class Teacher(models.Model):
    """讲师信息表"""
    nickname = models.CharField(max_length=30, primary_key=True, db_index=True, verbose_name="昵称")
    introduction = models.TextField(default="这位同学很懒,什么也没说", verbose_name="简介")
    fans = models.PositiveIntegerField(default=0, verbose_name="粉丝数")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    update_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")

    class Meta:
        verbose_name = "讲师信息表"
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.nickname


class Course(models.Model):
    """课程信息表"""
    title = models.CharField(max_length=100, primary_key=True, db_index=True, verbose_name="课程名")
    # 一对多
    # 删除级连
    teacher = models.ForeignKey(Teacher, null=True, blank=True, on_delete=models.CASCADE, verbose_name="课程讲师")
    # choice 对应 枚举 类型
    type = models.CharField(choices=((1, "实战课"), (2, "免费课"), (0, "其他")), max_length=1, default=0, verbose_name="课程类型")
    price = models.PositiveSmallIntegerField(verbose_name="课程价格")
    volume = models.BigIntegerField(verbose_name="销量")
    online = models.DateTimeField(verbose_name="上线时间")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    update_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")

    class Meta:
        verbose_name = "课程信息表"
        verbose_name_plural = verbose_name

    def __str__(self):
        return f"{self.get_type_display()}--{self.title}"  # 示例: 实战课--django入门


class Student(models.Model):
    """学生信息表"""
    nickname = models.CharField(max_length=30, primary_key=True, db_index=True, verbose_name="昵称")
    course = models.ManyToManyField(Course, verbose_name="所学课程")
    age = models.PositiveSmallIntegerField(verbose_name="年龄")
    gender = models.CharField(choices=((1, "男"), (2, "女"), (0, "保密")), max_length=1, default=0, verbose_name="性别")
    study_time = models.PositiveIntegerField(default=0, verbose_name="学习时长(h)")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    update_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")

    class Meta:
        verbose_name = "学生信息表"
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.nickname


class TeacherAssistant(models.Model):
    """助教信息表"""
    nickname = models.CharField(max_length=30, primary_key=True, db_index=True, verbose_name="昵称")
    teacher = models.OneToOneField(Teacher, null=True, blank=True, on_delete=models.SET_NULL, verbose_name="讲师")
    hobby = models.CharField(max_length=100, null=True, blank=True, verbose_name="爱好")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    update_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")

    class Meta:
        verbose_name = "助教信息"
        db_table = "courses_assistant"
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.nickname

django数据表操作

django导入数据表

import os
import sys
import random
import django
from datetime import date
# 这四行代码是在django项目中运行脚本
project_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(project_path)  # 将项目路径添加到系统搜寻路径中
os.environ['DJANGO_SETTINGS_MODULE'] = 'imooc.settings'  # 设置项目的配置文件
django.setup()

from courses.models import Teacher, Course, Student, TeacherAssistant


def import_data():
    # 使用django orm导入数据
    # 讲师数据 create()
    Teacher.objects.create(nickname='jack', introduction="python工程师", fans=666)
    Teacher.objects.create(nickname='Allen', introduction="java工程师", fans=123)
    Teacher.objects.create(nickname='henry', introduction="golang工程师", fans=818)

    # 课程数据 bulk_create()
    # 批量导入数据
    # 信息以列表形式传入
    # teacher是一个外键字段, 到通过orm导入数据时通过对象来进行关联
    # .get 返回一个teacher对象
    Course.objects.bulk_create([Course(title=f"python系列课程{i}", teacher=Teacher.objects.get(nickname="jack"),
                                       type=random.choice((0, 1, 2)),
                                       price=random.randint(200, 300), volume=random.randint(100, 10000),
                                       online=date(2018, 10, 1))
                                for i in range(1, 5)])
    Course.objects.bulk_create([Course(title=f"java系列课程{i}", teacher=Teacher.objects.get(nickname="Allen"),
                                       type=random.choice((0, 1, 2)),
                                       price=random.randint(200, 300), volume=random.randint(100, 10000),
                                       online=date(2018, 6, 4))
                                for i in range(1, 4)])
    Course.objects.bulk_create([Course(title=f"golang系列课程{i}", teacher=Teacher.objects.get(nickname="henry"),
                                       type=random.choice((0, 1, 2)),
                                       price=random.randint(200, 300), volume=random.randint(100, 10000),
                                       online=date(2018, 1, 1))
                                for i in range(1, 3)])

    # 学生数据 update_or_create()
    # 通过第一个参数去表中查询数据,如果存在更新后面defaults中的数据,如果不存在则创建一个新纪录
    # 应该把主键或者是具有唯一键属性的字段放在外面
    Student.objects.update_or_create(nickname="A同学", defaults={"age": random.randint(18, 58),
                                                              "gender": random.choice((1, 2, 0)),
                                                              "study_time": random.randint(9, 999)})
    Student.objects.update_or_create(nickname="B同学", defaults={"age": random.randint(18, 58),
                                                              "gender": random.choice((1, 2, 0)),
                                                              "study_time": random.randint(9, 999)})
    Student.objects.update_or_create(nickname="C同学", defaults={"age": random.randint(18, 58),
                                                              "gender": random.choice((1, 2, 0)),
                                                              "study_time": random.randint(9, 999)})
    Student.objects.update_or_create(nickname="D同学", defaults={"age": random.randint(18, 58),
                                                              "gender": random.choice((1, 2, 0)),
                                                              "study_time": random.randint(9, 999)})

    # 正向添加
    # 销量大于等于1000的课程
    # 通过学生(子表)关联到课程(父表)
    # 注意要是用 * 来解析
    Student.objects.get(nickname="A同学").course.add(*Course.objects.filter(volume__gte=1000))
    # 销量大于500的课程
    Student.objects.get(nickname="B同学").course.add(*Course.objects.filter(volume__gt=500))
    # 反向添加
    # 通过课程(父表)关联到学生(子表)
    # 学习时间大于等于500小时的同学
    # 表名_set 是固定写法
    Course.objects.get(title="Python系列课程1").student_set.add(*Student.objects.filter(study_time__gte=500))
    # 学习时间小于等于500小时的同学
    Course.objects.get(title="Python系列课程2").student_set.add(*Student.objects.filter(study_time__lte=500))

    # 助教数据 get_or_create()
    # 如果存在则get查询,如果不存在则创建一个新纪录
    # 与update_or_create类似
    TeacherAssistant.objects.get_or_create(nickname="助教1",
                                           defaults={"hobby": "学习", "teacher": Teacher.objects.get(nickname="jack")})
    TeacherAssistant.objects.get_or_create(nickname="助教2",
                                           defaults={"hobby": "舔狗", "teacher": Teacher.objects.get(nickname="Allen")})
    TeacherAssistant.objects.get_or_create(nickname="助教3",
                                           defaults={"hobby": "减肥", "teacher": Teacher.objects.get(nickname="henry")})

    return True


if __name__ == "__main__":
    if import_data():
        print("导入成功")


"""
    fixtures 也是一个提供数据初识化的方法
    提供一个能被django serialization识别的序列化文件
    可自动转化为model,保存到数据库
    >>> python manage.py dumpdata > imooc.json # 他导出的是数据库中所有的数据
    >>> python manage.py loaddata imooc.json # 进行导入
"""

models api

查询集介绍

# 一个视图类
class IndexView(View):
    def get(self, request):
        # 1.查询、检索、过滤
        # objects 是模型类的对象管理器
        # all() 取出所有结果
        teachers = Teacher.bojects.all()
        print(teachers)
        # get() 智能返回一条结果, 多条则会报错
        # 所以传入的的大多是主键或是唯一键
        teachers2 = Teacher.objects.get(nickname="jack")
        # 返回的是模型类
        print(teachers2, type(teachers2))
        # 返回的是 QuerySet 可以是多条结果
        teachers3 = Teacher.objects.filter(fans__gte=500)
        for t in teachers3:
            print(f"讲师姓名{t.nickname}--粉丝数:{t.fans}")

        # 2.字段数据匹配,大小写敏感
        # 在匹配字段时必须使用双下滑线
        # get:大于等于, exact:等于, gt:大于, in:在某某之内, isnull:是否为空, lt:小于, lte:小于等于, range:在某某范围内
        teacher4 = Teacher.objects.filter(fans__in=[666, 123])
        print(teacher4)
        # contains:含有, icontains:(大小写不敏感)含有, endwith:以某某结尾, iendwith:(大小写不敏感)以某某结尾, regex:正则表达
        teacher5 = Teacher.objects.filter(nickname__icontains='A')
        print(teacher5)

        # 3.结果切片、排序、链式查询
        print(Teacher.objects.all()[:1])
        # 默认升序排列,有 - 是降序
        teacher6 = Teacher.objects.all().order_by("-fans")
        for t in teacher6:
            print(t.fans)

        # 4.查看原生的SQL语句
        print(str(Teacher.objects.filter(fans__get==500).order_by('nickname')))
        return render(request, 'address.html')

返回QuerySet的API

"""返回新QuerySet API"""
# 1.all(),filter(),order_by(),exclude(),reverse(),distinct()
# exclude排除一些记录
print(Student.objects.all().exclude(nickname="A同学"))
# reverse()表示对结果反省排序, 要使用该api必须先对模型的元数据上设置ordering
# distinct() 去重
# 2.extra(),defer(),only()  实现字段别名,排除一些字段,选择一些字段
# 使用extra()为字段取别名
# key:别名, value:字段名
s3 = Student.objects.all().extra(select={"name": "nickname"})
# defer() 排除某些字段
# only() 只包括某些字段
print(str(Student.objects.all().only('nickname', 'age').query))
# 3.values(),values_list()  获取字典或元组形式的QuerySet
# values() 以字典列表形式返回
print(TeacherAssistant.objects.values('nickname', 'hobby'))
# <QuerySet [{'nickname':1, 'hobby':1}]>
# values_list() 以元组列表形式返回
print(TeacherAssistant.objects.values_list('nickname', 'hobby'))
#<QuerySet [('1','1')]>
# 当使用values_list() 只取一个字段时,可以使用flat=True
print(TeacherAssistant.objects.values_list('nicknaame',flat=True))
# <QuerySet ['1','1']>
# 4.dates(),datetimes()  根据时间获取查询集
# 参数分别为 查询字段, 查询种类, 排序顺序
# dates() 可以查 年月日, order默认为 ASC 正序,DESC是倒叙
print(Course.objects.dates('created_at', 'year', order='DESC'))
# 可以查 年月日时分秒
print(Course.objects.datestimes('created_at', 'year', order='DESC'))
# 5.union(),intersection(),difference()  交集,并集,差集
p_240 = Course.objects.filter(price__gte=240)
p_260 = Course.objects.filter(price__gte=260)
# 取交集
print(p_240.union(p_260))
# MYSQL只允许取交集
# 并集
print(p_240.intersection(p_260))
# 差集
print(p_240.difference(p_260))
# 6.select_related()  一对一,多对一查询优化, prefetch_related() 一对多,多对多查询优化; 反向查询
# select_related() 减少查询时所用SQL语句次数
course = Course.objects.all().select_related('teacher')
for c in course:
    print(f"{c.title}--{c.teacher}--{c.teacher.fans}")

students = Student.objects.filter(age__lt=30).prefetch_rlated()
for s in students:
    print(s.course.all())
# 7.annotate()  使用聚合计数,求和,平均数 raw() 执行原生的SQL
from django.db.models import COunt, Avg, Max, Min, Sum
print(Course.objects.values('teacher').annotate(vol=Sum('volume')))
print(Course.objects.values('teacher').annotate(pri=Avg('price')))

不返回QuerySet的API

"""不返回QuerySet API"""
# 1.获取对象 get(),get_or_create(),first(),last(),latest(),earliest(),in_bulk()
# first()获取第一个记录,last()获取最后一个
print(Course.objcets.first())
# 使用 latest()和earliest 必须在模型的元数据中设置 get_latest_by
# latest 表示最新的记录, earliest表示最早的记录,需要设定一个字段作为判断依据
print(Course.objcets.lastest())
# in_bulk 表示批量返回对象
print(Course.objcets.in_bulk(['python系列教程1', 'java系列教程']))
# 2.创建对象 create(), bulk_create(),update_or_create() 创建,批量创建,创建或更新
# 3.更新对象 update() ,update_or_create() 更新,更新或创建
Course.objcets.filter(title='Java系列教程').update(price=300)
# 3.删除对象 delete() 使用filter过滤
# 不要使用get 没有返回对象或返回多个对象会报错
Course.objcets.filter(title='test').delete()
# 4.其他操作 exists() count() aggregate() 判断是否存在,统计个数,聚合
print(Course.objcets.filter(title='test').exists())
print(Course.objcets.count())
# arrregate 对整个数据表中的数据进行统计
from django.db.models import COunt, Avg, Max, Min, Sum
print(Course.objcets.aggregate(Max('price'), Min('price'), Avg('price'), Sum('volume')))

自定义聚合查询

在模型类中定义

class GroupConcat(models.Aggregate):
    """自定义实现聚合功能,实现GROUP_CONCAT功能"""
    function = 'GROUP_CONCAT'
    # SQL语句
    template = '%(function)s(%(distinct)s%(expressions)s%(ordering)s%(separator)s)'

    def __init__(self, expression, distinct=False, ordering=None, separator=',', **extra):
        super(GroupConcat, self).__init__(expression,
                                          distinct='DISTINCT' if distinct else '',
                                          ordering=' ORDER BY %s' % ordering if ordering is not None else '',
                                          separator=' SEPRATOR "%s' % separator,
                                          output_field=models.CharField(), **extra)

使用自定义聚合查询

# 先引入
from .moudels import GroupConcat

# 使用
courses = Course.object.values('teacher').annotate(title=GroupConcat('title',distinct=True,ordering='title ASC',
                                                                    separator='-'))

F对象与Q对象

使用F对象和Q对象必须先导入

from django.db.models.import F, Q
  • F对象的使用: 操作字段数据 ,可以同时操作表中一个字段的所有记录

    Course.objects.update(price=F('price')-11)
    # 两个字段进行比较,不过必须是相同类型
    print(Course.objects.filter(volume__lte=F('price')*10)
    
  • Q对象的使用: 结合AND, OR, NOT, &, |, ~实现复杂的查询

    print(Course.objects.filter(Q(title__icontains='java')&Q(volume__gte=5000))
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值