Django通过orm操作mysql

文章目录

  • 1、Django简介
  • 2、Mysql连接设置
  • 3、模型类字段和参数类型
  • 4、ORM
    • 4.1、先建模型类,在迁移数据库
    • 4.2、先建数据库,在建模型类
  • 5、数据库操作
    • 5.1、增
    • 5.2、查
      • 5.2.1、单表查询
      • 5.2.2、多表联合查询
      • 5.2.3、基于双下划线的跨表查询(基于join实现的)
      • 5.2.4、聚合查询
      • 5.2.5、分组查询
      • 5.2.6、F查询和Q查询
    • 5.3、改
    • 5.4、删

1、Django简介

    Django是用python语言写的开源web开发框架,并遵循MVC设计。对比Flask框架,Django原生提供了众多的功能组件,让开发更简便快速。
    采用MVC程序设计模式,其核心思想是分工、解耦,让不同的代码块之间降低耦合,增强代码的可扩展性和可移植性,实现向后兼容。
    数据库支持ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库,这极大的减轻了开发人员的工作量。

2、Mysql连接设置

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

# DATABASES = {
#     'default': {
#         'ENGINE': 'django.db.backends.sqlite3',
#         'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
#     }
# }
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': "orm",  # 数据库提前创建好
        "HOST":"127.0.0.1",
        "port":3306,
        "USER":"root",
        "PASSWORD":"123456"
    }
}

让Django的ORM能以mysqldb的方式来调用PyMySQL,使用MySQL数据库首先需要安装驱动程序

pip install PyMySQL

在Django的工程目录的__init__.py中添加如下语句:

import pymysql
pymysql.install_as_MySQLdb()

Django通过orm操作mysql_第1张图片

3、模型类字段和参数类型

字段类型

类型 说明
AutoField 自增字段
CharField 字符串,参数max_length表示最大字符数
TextField 大文本字段
IntegerField 整数
DecimaField 十进制浮点数,参数max_digits表示总位数,不包括符号,参数decimal_places表示小数位数
FloatField 浮点数
DateField 日期, 参数auto_now表示每次保存对象时,自动设置该字段为当前时间,用于"最后一次修改"的时间戳,它总是使用当前日期,默认为False; 参数auto_now_add表示当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为False; 参数auto_now_add和auto_now是相互排斥的,组合将会发生错误
TimeField 时间
DateTimeField 日期时间
FileField 文件字段
BooleanField 布尔字段
ImageField 继承于FileField,对上传的内容进行校验,确保是有效的图片
ForeignKey 外键
OneToOneField 一对多
ManyToManyField 多对多

参数

参数 说明
null 表示是否允许为空,默认为False
blank 在表单中该字段是否允许为空,默认为False
db_index 是否创建为索引,默认为False
db_column 自定义字段名称
default 默认值
primary_key 若为True,则该字段设置为主键字段,一般和AutoField搭配
unique 唯一值,默认False
verbose_name 指定在admin管理界面中显示中文;verbose_name表示单数形式的显示,verbose_name_plural表示复数形式的显示
choices 二元组组成的一个可迭代对象,用来给字段提供选择项
auto_now_add 创建数据记录的时候会把当前时间添加到数据库,默认为Fasle
auto_now 每次更新数据记录的时候会更新该字段,标识这条记录最后一次的修改时间,默认为False
on_delete 在设置外键时,需要通过on_delete选项指明主表删除数据时,对于外键引用表数据如何处理:CASCADE级联,删除主表数据时连通一起删除外键表中数据;PROTECT保护,通过抛出ProtectedError异常,来阻止删除主表中被外键应用的数据;SET_NULL设置为NULL,仅在该字段null=True允许为null时可用;SET_DEFAULT设置为默认值,仅在该字段设置了默认值时可用SET()设置为特定值或者调用特定方法;DO_NOTHING不做任何操作,如果数据库前置指明级联性,此选项会抛出IntegrityError异常
Foreignkey中参数 to:设置要关联的表;to_field:设置要关联的表的字段;related_name:反向操作时,使用的字段名,用于代替原反向查询时的’表名_set’;related_query_name:反向查询操作时,使用的连接前缀,用于替换表名;on_delete;当删除关联表中的数据时,当前表与其关联的行的行为。
ForeignKey的db_contraint 只有关联关系,没有强制的约束关系
元信息(Meta db_table:ORM在数据库中的表名,默认是 app_类名。index_together:联合索引。unique_together:联合唯一索引。ordering:指定默认按什么字段排序。

4、ORM

4.1、先建模型类,在迁移数据库

创建模型类,在models.py

from django.db import models

class Teacher(models.Model):

    id = models.AutoField(primary_key=True,verbose_name="教师id")
    name = models.CharField(max_length=4,null=False,verbose_name="教师名称")
    age = models.IntegerField(default=40,verbose_name="教师年龄")
    gender_list = ((1,"男"),(2,"女"),(3,"其他"))
    gender = models.IntegerField(default=1,choices=gender_list,verbose_name="性别")
    phone = models.CharField(max_length=11,null=False,verbose_name="手机号")

    class Meta:
        db_table = "teacher"
        verbose_name = "教师表"
        verbose_name_plural = verbose_name

#教师表和课程一对一的关系
class Course(models.Model):

    id = models.AutoField(primary_key=True,verbose_name="课程id")
    name = models.CharField(max_length=16,null=False,verbose_name="课程名称")
    teacher = models.OneToOneField(to="Teacher",to_field="id",on_delete=models.CASCADE,related_name="course")

    class Meta:
        db_table = "course"
        verbose_name = "课程表"
        verbose_name_plural = verbose_name
#学生表和课程表是多对多关系
class Student(models.Model):

    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=4,null=False,verbose_name="学生姓名")
    age = models.IntegerField(default=20,verbose_name="年龄")
    gender_list = ((1,"男"),(2,"女"),(3,"其他"))
    gender = models.IntegerField(choices=gender_list,default=1,verbose_name="性别")
    phone = models.CharField(max_length=11,null=False,verbose_name="手机号")
    course = models.ManyToManyField(to="Course",through="StudentCourse",through_fields=("student_id","course_id"),related_name="student")

    class Meta:
        db_table = "student"
        verbose_name = "学生表"
        verbose_name_plural = verbose_name

    def __str__(self):
        return f"{self.id}:{self.name}"
#学生表和课程表的中间表
class StudentCourse(models.Model):

    id = models.AutoField(primary_key=True)
    student_id = models.ForeignKey(to="Student",verbose_name="学生id")
    course_id = models.ForeignKey(to = "Course",verbose_name="课程id")

    class Meta:
        db_table = "student_course"
        unique_together = ("student_id","course_id")
# 分数表和课程表、学生表是一对多关系
class Grade(models.Model):

    id = models.AutoField(primary_key=True,verbose_name="分数id")
    score = models.DecimalField(default=0,decimal_places=1,max_digits=4,null=False,verbose_name="分数")
    student_id = models.ForeignKey(to="Student",to_field="id",on_delete=models.CASCADE,related_name="grade")
    course_id = models.ForeignKey(to="Course",to_field="id",on_delete=models.CASCADE,related_name="grade")

    class Meta:
        db_table = "grade"
        verbose_name = "分数表"
        verbose_name_plural = verbose_name

迁移

# 终端上输入
#生成迁移文件
python manage.py makemigrations
#同步到数据库中
python manage.py migrate

4.2、先建数据库,在建模型类

在MySQL中创建表,然后再models.py上创建模型类

create table student(
    id int primary key auto_increment comment "学生id",
    sname varchar(4) not null comment "姓名",
    gender enum("男","女") default "男" comment "性别",
    phone char(11) not null comment "手机号"
) engine="innodb",charset="utf8",comment="学生表";

create table teacher(
    id int primary key auto_increment comment "老师id",
    tname varchar(4) not null comment "老师姓名",
    gender enum("男","女") default "男" comment "性别",
    phone char(11) not null comment "手机号"
) engine="innodb" default charset=utf8 comment="教师表";

create table course(
    id int primary  key auto_increment comment "课程id",
    cname varchar(10) not null comment "课程名",
    teacher int default null comment "老师id",
    constraint c_t_key foreign key(teacher) references teacher(id)
) engine="innodb" default charset=utf8 comment="课程表";

create table grade(
    id int primary key auto_increment comment "分数id",
    score float default 0 comment "分数",
    student int default null comment "学生id",
    course int default null comment "课程id",
    constraint g_s_key foreign key(student) references student(id),
    constraint g_c_key foreign key(course) references course(id)
) engine="innodb" default charset=utf8 comment "分数表";

create table student_course(
    id int primary  key auto_increment comment "学生课程id",
    sid int default null comment "学生id",
    cid int default null comment "课程id",
    constraint s_s_c foreign key(sid) references student(id),
    constraint c_s_c foreign key(cid) references course(id)
) engine="innodb" default charset=utf8 comment="学生课程表";

5、数据库操作

5.1、增

单表添加

# obj.save()单个增加
student = models.Student(name = "张三",gender=1,phone="12345678910")
student.save()
#create()新增---常用
student = models.Student.objects.create(name = "李四",gender=2,phone="12345678911")
#bulk_create(list)批量增加
students = []
names = ["王五","李六","刘七"]
for i,name in enumerate(names,2):
    stu = models.Student(name = name,gender=1,phone="1234567891" + str(i))
    students.append(stu)
stus = models.Student.objects.bulk_create(students)

一对一、一对多、多对多添加

teachers = models.Teacher.objects.all()
courses=["语文","数学","英语"]
for i,teacher in enumerate(teacher,1):
    #根据数据库中字段名赋值
    # course = models.Course.objects.create(name=courses[i],teacher_id=teacher.id)
    #直接传对象
    course = models.Course.objects.create(name=courses[i], teacher=teacher)

5.2、查

5.2.1、单表查询

#返回与所给筛选条件相匹配的对象,返回结果有且只有一个,多个会报错
student = models.Student.objects.get(id=1)
#查询表所有结果
student_query = models.Student.objects.all()
# 返回第一个数据对象
student_first = models.Student.objects.first()
#返回第二个数据对象
student_last = models.Student.objects.last()
#查询除了id为1的学生,类型为querySet
students = models.Student.objects.exclude(id=1)
#判断是否包含数据
student = models.Student.objects.all().exists()
#  返回查询结果的个数
count = models.Student.objects.all().count()
#  对values返回结果中剔除重复纪录
students = models.Student.objects.all().values("id","name").distinct()
#查询指定字段,querySet里包含字典
students = models.Student.objects.filter(gender=1).values("id","name")
# querySet里包含元组
students = models.Student.objects.filter(gender=1).values_list("id", "name")
#聚合:Count,Sum,Avg,Max,Min,返回querySet列表
#from django.db.models import Count,Max,Min,Sum,Avg
student = models.Student.objects.values('gender').annotate(gid=Count('gender'))
# 永远sql语句
student = models.Student.objects.raw("select * from student")
# 聚合函数,获取字典类型聚合结果  {'gender_c': 2, 'id_c': 5}按性别分由两组,学生id分有5组
student = models.Student.objects.aggregate(gender_c=Count('gender', distinct=True), id_c=Count('id'))
# 基于双下划线的模糊查询
student = models.Student.objects.filter(gender__in=[1,2,3])
# 大于
student = models.Student.objects.filter(age__lt=20)
# 小于
student = models.Student.objects.filter(age__gt=20)
# 大于或等于
student = models.Student.objects.filter(age__gte=20)
# 开头匹配
student = models.Student.objects.filter(phone__startswith="123")
#模糊查询
student = models.Student.objects.filter(name__contains="张").values("name")
#判断是否为空
student = models.Student.objects.filter(name__isnull=True)
#排序
#升序
student = models.Student.objects.order_by("age")
#降序
student = models.Student.objects.order_by("-age")

5.2.2、多表联合查询

#正向查询(按字段:课程表的teacher):关联属性字段所在的表查询被关联表的记录就是正向查询,反之就是反向查询

#一对一或者一对多
course = models.Course.objects.first()
teacher = course.teacher # ---对象
#反向查询(按表名course_set或者通过设置related_name=“course”代替'表名_set'。,因为加上_set是因为反向查询的时候,你查询出来的可能是多条记录的集合):
teacher = models.Teacher.objects.first()
# 得到queryset类型数据
course = teacher.course_set.all()    或
course = teacher.course.all()
# 多对多,正向反向返回都是queryset类型
#正向
student = models.Student.objects.first()
courses = student.course.all()
#反向
course = models.Course.objects.first()
students = course.student_set.all()    或
students = course.student.all()

5.2.3、基于双下划线的跨表查询(基于join实现的)

# 一对一、一对多、多对多方法都一样
# 正向
grade = models.Grade.objects.filter(student_id__name="张三").values("score")
# 反向
grade = models.Student.objects.filter(name="张三").values("grade__score")
# 正向
student = models.Student.objects.filter(course__name="数学").values("name")
# 反向
student = models.Course.objects.filter(name="数学").values("student__name")
#连续跨表查询
# 正向
grade = models.Grade.objects.filter(student_id__name="张三").values("score","course_id__name")
#反向
grade = models.Student.objects.filter(name="张三").values("grade__score","grade__course_id__name")

5.2.4、聚合查询

#所有人平均分-----aggregate的返回值是一个字典类型
grade_agv = models.Grade.objects.all().aggregate(score_avg=Avg("score"))
# 某个人的平均分
student_agv = models.Grade.objects.filter(student_id__name="张三").aggregate(score_avg=Avg("score"))
#求多个聚合
score = models.Grade.objects.aggregate(avg_s=Avg("score"),max_s = Max("score"),min_s = Min("score"))

5.2.5、分组查询

annotate()为调用的QuerySet中每一个对象都生成一个独立的统计值(统计方法用聚合函数

#根据学生姓名分组,求分数平均值,和分数最大值
#正向
grade = models.Grade.objects.values("student_id__name").annotate(avg_s = Avg("score"),max_s=Max("score"))
#反向
score = models.Student.objects.annotate(avg_s=Avg("grade__score"),max_s=Max("grade__score"),min_s=Min("grade__score"))

5.2.6、F查询和Q查询

上面查询只是将字段值与某个常量做比较。F和Q查询可以对两个字段的值做比较

# F可以比较两个不同字段的值
# 查询学生课程连表,课程id=学生id的数据
from django.db.models import F
sc = models.StudentCourse.objects.filter(course_id=F('student_id'))
# F对象支持和常数之间的加减乘除和取模的操作
sc = models.StudentCourse.objects.filter(course_id=F('student_id')+1).all()
sc = models.StudentCourse.objects.filter(course_id=F('student_id')*2).all()
Q 对象可以使用&|~ 操作符组合起来。当一个操作符在两个Q 对象上使用时,它产生一个新的Q 对象。
from django.db.models import Q
# or查询
students = models.Student.objects.filter(Q(name="张三")| Q(name="李四"))
# 查询名字为张三或者,没选数学课程的学生
students = models.Student.objects.filter(Q(name="张三") | ~Q(course__name="数学")).values("name")
# 复杂的查询
students = models.Student.objects.filter((Q(age__lt=20) & Q(grade__score__gt=70)) | (Q(age__gt=24) & Q(grade__score__lt=60))).values("name")

5.3、改

# update更新
res = models.Student.objects.filter(name="张三").update(name="章三")
# save更新
student = models.Student.objects.filter(name="章三").first()
student.name = "张三"
student.save()

5.4、删

# delete删除
models.Student.objects.filter(name="张三").delete()
# 对象delete删除
student = models.Student.objects.get(id=2)
student.delete()

你可能感兴趣的:(数据库,django,mysql,python)