Django是用python语言写的开源web开发框架,并遵循MVC设计。对比Flask框架,Django原生提供了众多的功能组件,让开发更简便快速。
采用MVC程序设计模式,其核心思想是分工、解耦,让不同的代码块之间降低耦合,增强代码的可扩展性和可移植性,实现向后兼容。
数据库支持ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库,这极大的减轻了开发人员的工作量。
在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()
字段类型
类型 | 说明 |
---|---|
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:指定默认按什么字段排序。 |
创建模型类,在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
在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="学生课程表";
单表添加
# 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)
#返回与所给筛选条件相匹配的对象,返回结果有且只有一个,多个会报错
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")
#正向查询(按字段:课程表的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()
# 一对一、一对多、多对多方法都一样
# 正向
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")
#所有人平均分-----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"))
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"))
上面查询只是将字段值与某个常量做比较。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")
# update更新
res = models.Student.objects.filter(name="张三").update(name="章三")
# save更新
student = models.Student.objects.filter(name="章三").first()
student.name = "张三"
student.save()
# delete删除
models.Student.objects.filter(name="张三").delete()
# 对象delete删除
student = models.Student.objects.get(id=2)
student.delete()