模型,就是python中的类对应数据库中的表
ORM 就是通过实例对象的语法,完成关系型数据库的操作的技术,是"对象-关系映射"(Object/Relational Mapping) 的缩写。
1.模型类生成数据库表
1.创建项目
在cmd中运行:
#创建项目
django-admin startproject model_study
#进入项目目录创建子应用
python manage.py startapp model_app
2.配置应用
1.将模型对应的应用程序添加到项目的settings中:
INSTALLED_APPS = [
'model_app'
]
2.在settings中配置正确的数据库连接:
# sqlite3
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# mysql
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'model_study',
'USER': 'root',
'PASSWORD': 'root',
'HOST': '127.0.0.1',
'PORT': '3306',
}
}
3.编写模型
from django.db import models
# 创建模型类必须继承models.Model
class Question(models.Model):
question_title=models.CharField(max_length=20,default="")
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField()
4. 预备迁移
在cmd项目根目录中运行
python manage.py makemigrations model_app
5.正式迁移
在cmd项目根目录中运行
python manage.py migrate
2.数据库表逆向生成模型类
在根目录的cmd中运行:
python manage.py inspectdb > model_app/models.py
3.Field字段
1.命名规则:数字,字母,下划线组成,字母不能在开头,且不能为Python保留字
2.AutoField和primary_key
默认会自动创建一个自增,主键的id列,如果指定了 primary_key 为其它列,那么不会自动创建id 列 可以在模型中指定:
id = models.AutoField(primary_key=True)
3.常见Field
所有的Field类型,见 Field类型
常见的Field类型:
AutoField
BooleanField
CharField
DateField
DateTimeField
FloatField
SmallIntegerField
IntegerField
TextField
4.Field常见参数
- max_length:字段最大长度,用于字符串等,字符串类型CharField必须设置该值
- null:如果True,Django将在数据库中存储NULL空值。默认是False
- blank:如果True,该字段被允许为空白("")。默认是False。请注意,这不同于null。null纯粹是与数据库相关的,而blank与验证相关。如果一个字段有blank=True,表单验证将允许输入一个空值。如果一个字段有blank=False,该字段将是必需的。
- choices:示例:YEAR_IN_SCHOOL_CHOICES = (('FR', 'Freshman'),('SO', 'Sophomore'),('JR', 'Junior'),('SR', 'Senior'),('GR', 'Graduate')) ,中文示例:SEX_CHOICES=((1, '男'),(2, '女')),元组中的第一个元素是将存储在数据库中的值,第二个元素是将在页面中显示的值,最常见用于下拉选择框select
- default:字段的默认值
- help_text:用于显示额外的“帮助”文本
- primary_key:如果True,这个字段是模型的主键,默认是False
- unique:如果True,该字段在整个表格中必须是唯一的
- verbose_name:详细字段名,不指定则是属性名的小写,并且用 空格 替换 '_'
5、模型之间的关系
-
主外关系中,关联操作最常用的是: models.CASCADE 级联删除 和 models.SET_NULL 设置为null
-
一对多关系中,ForeignKey 写在一对多关系中,多的那个模型中
1.一对一关系
OneToOneField写在任何一方都可以
from django.db import models
# Create your models here.
class Place(models.Model):
name=models.CharField(max_length=20)
address=models.CharField(max_length=20)
def __str__(self):
return f"the place's name is {self.name}"
class School(models.Model):
place=models.OneToOneField(
Place,
on_delete=models.CASCADE,
primary_key=True
)
name=models.CharField(max_length=20)
has_teacher=models.BooleanField(default=True)
has_car=models.BooleanField(default=False)
def __str__(self):
return f"the school's name is {self.place}"
2.一对多关系
ForeignKey写在多的一方
from django.db import models
# Create your models here.
class Teacher(models.Model):
name=models.CharField(max_length=20)
class Student(models.Model):
teacher=models.ForeignKey(Teacher,on_delete=models.CASCADE)
name=models.CharField(max_length=20)
3.多对多关系
from django.db import models
# Create your models here.
# 1.自关联
# ManyToManyField写在本类中
class Student(models.Model):
name=models.CharField(max_length=10)
friends=models.ManyToManyField("self")
# 2.多对多
class schoolClass(models.Model):
name=models.CharField(max_length=10)
class Teacher(models.Model):
name=models.CharField(max_length=10)
school_class=models.ManyToManyField(schoolClass)
# 3.自定义中间表
class Person(models.Model):
name=models.CharField(max_length=10)
class Group(models.Model):
name=models.CharField(max_length=10)
members=models.ManyToManyField(
Person,
through="MemberShip",
through_fields=("group","person")
)
class MemberShip(models.Model):
person=models.ForeignKey(Person,on_delete=models.CASCADE)
group=models.ForeignKey(Group,on_delete=models.CASCADE)
level=models.IntegerField(default=1)
4.方法(数据的相关操作)
在根目录的cmd执行:
python manage.py shell
首先导入模块,通过导入的模块中的模型对象objects属性执行操作
1.新增:
save或create
1.一对多关系新增:
from django.db import models
# Create your models here.
class Teacher(models.Model):
name=models.CharField(max_length=20)
class Student(models.Model):
teacher=models.ForeignKey(Teacher,on_delete=models.CASCADE)
name=models.CharField(max_length=20)
方法一:
在创建Student实例对象的时候对teacher进行赋值
>>> from one_more_app.models import *
>>> Teacher.objects.create(name="王老师")
<Teacher: Teacher object (1)>
>>> Teacher.objects.create(name="李老师")
<Teacher: Teacher object (2)>
# 根据查询到的数据进行赋值
>>> t=Teacher.objects.get(pk=1)
>>> t
<Teacher: Teacher object (1)>
>>> Student.objects.create(teacher=t,name="xialei")
<Student: Student object (1)>
方法二:
创建完Student实例对象后再对类属性teacher赋值
>>> t=Teacher.objects.get(pk=2)
>>> t
<Teacher: Teacher object (2)>
>>> s=Student(name="zmy")
>>> s.teacher=t
>>> s.save()
2.多对多关系新增:
先各自都创建实例对象,再进行关联操作
from django.db import models
class schoolClass(models.Model):
name=models.CharField(max_length=10)
class Teacher(models.Model):
name=models.CharField(max_length=10)
school_class=models.ManyToManyField(schoolClass)
>>> from more_more_app.models import *
>>> schoolClass.objects.create(name="class1")
<schoolClass: schoolClass object (1)>
>>> schoolClass.objects.create(name="class2")
<schoolClass: schoolClass object (2)>
>>> schoolClass.objects.create(name="class3")
<schoolClass: schoolClass object (3)>
>>> Teacher.objects.create(name="zhangsan")
<Teacher: Teacher object (1)>
>>> Teacher.objects.create(name="lisi")
<Teacher: Teacher object (2)>
>>> Teacher.objects.create(name="xialei")
<Teacher: Teacher object (3)>
>>> t=Teacher.objects.get(pk=3)
>>> t
<Teacher: Teacher object (3)>
# set方法不会增加,而是重新赋值
>>> t.school_class.set([2,3])
# add方法增加
>>> t.school_class.add(1)
2.查询
1.过滤器:
from django.db import models
# Create your models here.
class Question(models.Model):
question_title=models.CharField(max_length=20,default="")
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField()
(1)get获取一个对象
>>> Question.objects.get(id=1)
<Question: Question object (1)>
>>> Question.objects.get(question_title='c')
<Question: Question object (3)>
(2)all获取多个对象
>>> Question.objects.all()
<QuerySet [<Question: Question object (1)>, <Question: Question object (2)>, <Question: Question object (3)>]>
(3)filter过滤
>>> Question.objects.filter(question_title="c")
<QuerySet [<Question: Question object (3)>]>
>>> Question.objects.filter(id=2)
<QuerySet [<Question: Question object (2)>]>
2.字段查找
完整的字段查找文档:字段检索
常见的字段检索:
exact :判断是否等于value,一般不使用,而直接使用 '='
>>> Question.objects.get(id__exact=3)
<Question: Question object (3)>
contains:是否包含,大小写敏感,如果需要不敏感的话,使用icontains
>>> Question.objects.filter(question_title__contains='j')
<QuerySet [<Question: Question object (2)>]>
>>> Question.objects.filter(question_title__contains='J')
<QuerySet []>
>>> Question.objects.filter(question_title__iscontains='J')
>>> Question.objects.filter(question_title__icontains='J')
<QuerySet [<Question: Question object (2)>]>
startswith:以value开头,大小写敏感
>>> Question.objects.filter(question_title__startswith="java")
<QuerySet [<Question: Question object (2)>, <Question: Question object (4)>]>
endwith:以value结尾,大小写敏感
>>> Question.objects.filter(question_title__endswith="s")
<QuerySet [<Question: Question object (4)>]>
in:是否包含在范围内
>>> Question.objects.filter(id__in=[1,2,4])
<QuerySet [<Question: Question object (1)>, <Question: Question object (2)>, <Question: Question object (4)>]>
isnull:是否为null, 如:filter(name__isnull=Flase)
>>> Question.objects.filter(id__isnull=False)
<QuerySet [<Question: Question object (1)>, <Question: Question object (2)>, <Question: Question object (3)>, <Question: Question object (4)>]>
gt:大于,如:filter(sage__gt=30) , 年龄大于30
>>> Question.objects.filter(id__gt=2)
<QuerySet [<Question: Question object (3)>, <Question: Question object (4)>]>
gte:大于等于
>>> Question.objects.filter(id__gte=2)
<QuerySet [<Question: Question object (2)>, <Question: Question object (3)>, <Question: Question object (4)>]>
lt:小于
>>> Question.objects.filter(id__lt=2)
<QuerySet [<Question: Question object (1)>]>
lte:小于等于
>>> Question.objects.filter(id__lte=2)
<QuerySet [<Question: Question object (1)>, <Question: Question object (2)>]>
3.日期时间的过滤
(1)使用gt,gte,lt,lte
>>> Question.objects.filter(pub_date__gt="2015-2-20")
<QuerySet [<Question: Question object (2)>, <Question: Question object (3)>]>
(2)__range查询时间段
>>> Question.objects.filter(pub_date__range=["2010-1-03","2015-2-23"])
<QuerySet [<Question: Question object (1)>, <Question: Question object (4)>]>
(3)__date查询某年某月某日
>>> Question.objects.filter(pub_date__date="2022-03-22")
<QuerySet [<Question: Question object (2)>]>
(4)__year查询某年
>>> Question.objects.filter(pub_date__year="2011")
<QuerySet [<Question: Question object (1)>, <Question: Question object (4)>]>
exclude:例外
>>> Question.objects.exclude(pub_date__year="2011")
<QuerySet [<Question: Question object (2)>, <Question: Question object (3)>]>
(5)filter获取对象列表,支持切片但是不支持负数切片
>>> Question.objects.filter(pub_date__gt="2000-1-2")
<QuerySet [<Question: Question object (1)>, <Question: Question object (2)>, <Question: Question object (3)>, <Question: Question object (4)>]>
>>> Question.objects.filter(pub_date__gt="2000-1-2")[:2]
<QuerySet [<Question: Question object (1)>, <Question: Question object (2)>]>
6)__month查询某月
(7)__day查询某日
(8)__week_day查询星期几(1-7)
4.排序
order_by:默认按照升序排列
>>> Question.objects.filter(pub_date__year="2011").order_by("pub_date")
<QuerySet [<Question: Question object (4)>, <Question: Question object (1)>]>
order_by括号后传入的参数前加“-”表示降序排列
>>> Question.objects.filter(pub_date__year="2011").order_by("-pub_date")
<QuerySet [<Question: Question object (1)>, <Question: Question object (4)>]>
5.其他方法
(1)count对结果集进行计数
>>> Question.objects.filter(pub_date__year="2011").count()
2
(2)reverse对结果集进行反转,可改变无法反向切片的不足之处,使用前必须先排序
>>> Question.objects.filter(pub_date__year="2011").order_by("pub_date")
<QuerySet [<Question: Question object (4)>, <Question: Question object (1)>]>
>>> Question.objects.filter(pub_date__year="2011").order_by("pub_date").reverse()
<QuerySet [<Question: Question object (1)>, <Question: Question object (4)>]>
>>> Question.objects.filter(pub_date__year="2011").order_by("pub_date").reverse()[:1]
<QuerySet [<Question: Question object (1)>]>
(3)first返回结果集的第一个对象
>>> Question.objects.filter(pub_date__gt="2000-2-2")
<QuerySet [<Question: Question object (1)>, <Question: Question object (2)>, <Question: Question object (3)>, <Question: Question object (4)>]>
>>> Question.objects.filter(pub_date__gt="2000-2-2").first()
<Question: Question object (1)>
(4)last返回结果集的最后一个对象
>>> Question.objects.filter(pub_date__gt="2000-2-2")
<QuerySet [<Question: Question object (1)>, <Question: Question object (2)>, <Question: Question object (3)>, <Question: Question object (4)>]>
>>> Question.objects.filter(pub_date__gt="2000-2-2").last()
<Question: Question object (4)>
(5)values返回一个字典对象列表
<QuerySet [{'id': 1, 'question_title': 'python', 'question_text': 'python is easy', 'pub_date': datetime.datetime(2011, 2, 23, 0, 0, tzinfo=datetime.timezone.utc)}, {'id': 2, 'question_title': 'java', 'question_text': 'java is difficult', 'pub_date': datetime.datetime(2022, 3, 22, 0, 0, tzinfo=datetime.timezone.utc)}, {'id': 3, 'question_title': 'c', 'question_text': 'c is boring', 'pub_date': datetime.datetime(2022, 3, 11, 0, 0, tzinfo=datetime.timezone.utc)}, {'id': 4, 'question_title': 'javaScripts', 'question_text': 'javaScripts是前端', 'pub_date': datetime.datetime(2011, 1, 30, 0, 0, tzinfo=datetime.timezone.utc)}]>
values传参:
>>> Question.objects.filter(pub_date__gt="2000-2-2").values("question_title")
<QuerySet [{'question_title': 'python'}, {'question_title': 'java'}, {'question_title': 'c'}, {'question_title': 'javaScripts'}]>
6.多对象关联查询
(1)一对一关系查询
from django.db import models
# Create your models here.
class Place(models.Model):
name=models.CharField(max_length=20)
address=models.CharField(max_length=20)
def __str__(self):
return f"the place's name is {self.name}"
class School(models.Model):
place=models.OneToOneField(
Place,
on_delete=models.CASCADE,
primary_key=True
)
name=models.CharField(max_length=20)
has_teacher=models.BooleanField(default=True)
has_car=models.BooleanField(default=False)
def __str__(self):
return f"the school's name is {self.place}"
通过一个模型获取另一个模型:通过定义OneToOneField的模型获取另一个模型
>>> school=School.objects.first()
>>> place=school.place
>>> place
<Place: the place's name is 安庆>
(2)一对多关系查询
from django.db import models
# Create your models here.
class Teacher(models.Model):
name=models.CharField(max_length=20)
class Student(models.Model):
teacher=models.ForeignKey(Teacher,on_delete=models.CASCADE)
name=models.CharField(max_length=20)
从一的模型查找多的模型,通过"多的模型的小写名_set"查找
>>> t=Teacher.objects.first()
>>> t
<Teacher: Teacher object (1)>
>>> s=t.student_set.all()
>>> s
<QuerySet [<Student: Student object (2)>]>
从多的模型查找一的模型
>>> s=Student.objects.first()
>>> s
<Student: Student object (2)>
>>> teacher=s.teacher
>>> teacher
<Teacher: Teacher object (1)>
(3)多对多关系查询
from django.db import models
# Create your models here.
class schoolClass(models.Model):
name=models.CharField(max_length=10)
class Teacher(models.Model):
name=models.CharField(maxt_length=10)
school_class=models.ManyToManyField(schoolClass)
从没有ManyToManyField的模型中查询有ManyToManyField的模型
>>> s=schoolClass.objects.first()
>>> t=s.teacher_set.all()
>>> t
<QuerySet [<Teacher: Teacher object (2)>]>
从有ManyToManyField的模型中查询没有ManyToManyField的模型
>>> t=Teacher.objects.first()
>>> t
<Teacher: Teacher object (1)>
>>> s=t.school_class.all()
>>> s
<QuerySet []>
7.聚合函数
使用aggregate()函数返回聚合函数的值
常用的聚合函数有:Avg、Count、Max、Min、Sum
使用前需要:from django.db.models import 聚合函数
>>> from django.db.models import Max,Min,Avg,Sum,Count
>>> Question.objects.aggregate(Max("id"),Min("id"),Sum("id"),Count("id"),Avg("id"))
{'id__max': 4, 'id__min': 1, 'id__sum': Decimal('10'), 'id__count': 4, 'id__avg': 2.5}
>>>
8.分组查询
使用annotate()函数实现分组查询,得配合其他函数:
- annotate:用于分组,配合 Avg,Count等聚合函数,如:annotate(max=Max('age'))
(即:所需要统计的数据)
- filter:用于过滤,在 annotate之前使用表示 where 条件,在annotate之后使用表示having条件
- values:在annotate之前使用表示分组字段,在annotate之后使用表示取值
(即:所需分组的字段)
from django.db import models
# Create your models here.
class schoolClass(models.Model):
name=models.CharField(max_length=10)
class Teacher(models.Model):
name=models.CharField(maxt_length=10)
school_class=models.ManyToManyField(schoolClass)
(1)查询每个班级有几位老师
Teacher模块有ManyToManyFiled,则values里面传入属性schoo_class即可
>>> from more_more_app.models import *
>>> teacher=Teacher.objects.values("school_class").annotate(Count("id"))
>>> teacher
<QuerySet [{'school_class': None, 'id__count': 1}, {'school_class': 1, 'id__count': 1}, {'school_class': 2, 'id__count': 2}, {'school_class': 3, 'id__count': 2}]>
filter表示where条件可以在annotate之前和之后使用,最好在之前使用,表示先过滤后分组,提 高效率;filter表示having条件必须在annotate之后使用,表示对所需统计数据进行过滤
>>> Teacher.objects.values("school_class").annotate(tcount=Count("id")).filter(name__contains="夏磊")
<QuerySet [{'school_class': 2, 'tcount': 1}, {'school_class': 3, 'tcount': 1}]>
>>> Teacher.objects.values("school_class").annotate(tcount=Count("id")).filter(tcount__gte=2)
<QuerySet [{'school_class': 2, 'tcount': 2}, {'school_class': 3, 'tcount': 2}]>
(2)查询每个老师带几个班
schoolClass模块没有ManyToManyFiled,则values里面传入模块Teacher的小写即可
>>> schoolClass.objects.values("teacher").annotate(Count("id"))
<QuerySet [{'teacher': 2, 'id__count': 3}, {'teacher': 3, 'id__count': 2}, {'teacher': None, 'id__count': 1}]>
3.修改
from django.db import models
# Create your models here.
class Question(models.Model):
question_title=models.CharField(max_length=20,default="")
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField()
(1)修改一条数据
>>> from model_app.models import *
>>> q=Question.objects.first()
>>> q
<Question: Question object (1)>
>>> q.question_text="python is interesting"
>>> q.save()
(2)修改多条数据
>>> Question.objects.filter(id__in=(1,3))
<QuerySet [<Question: Question object (1)>, <Question: Question object (3)>]>
>>> Question.objects.filter(id__in=(1,3)).update(pub_date="2000-12-11")
2
4.删除
from django.db import models
# Create your models here.
class Question(models.Model):
question_title=models.CharField(max_length=20,default="")
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField()
>>> Question.objects.get(pk=4).delete()
(1, {'model_app.Question': 1})
5.Q对象
filter() 等方法中的关键字参数查询都是并且('AND')的, 如果你需要执行更复杂的查询(例如or语句),那么可以使用Q 对象。
使用Q对象前需要:from django.db.models import Q
| , &:或,且运算符
>>> from django.db.models import Q
>>> Question.objects.filter(Q(question_title="java")|Q(question_title="c"))
<QuerySet [<Question: Question object (2)>, <Question: Question object (3)>]>
~Q:取反运算符
>>> Question.objects.filter(~Q(question_title="java"))
<QuerySet [<Question: Question object (1)>, <Question: Question object (3)>]>
注意:Q对象可以和一般关键字参数一起使用,但必须在一般关键字参数的前面
6.F对象
from django.db import models
class Person(models.Model):
name=models.CharField(max_length=10)
class Group(models.Model):
name=models.CharField(max_length=10)
members=models.ManyToManyField(
Person,
through="MemberShip",
through_fields=("group","person")
)
class MemberShip(models.Model):
person=models.ForeignKey(Person,on_delete=models.CASCADE)
group=models.ForeignKey(Group,on_delete=models.CASCADE)
level=models.IntegerField(default=1)
1.模型的属性名出现在操作符的右边,就使用F对象进行包裹
>>> from django.db.models import *
>>> MemberShip.objects.filter(group_id__gte=F("person_id"))
<QuerySet [<MemberShip: MemberShip object (1)>, <MemberShip: MemberShip object (3)>, <MemberShip: MemberShip object (5)>]>
2.可用于计算
>>> MemberShip.objects.filter(person_id=1).update(level=F("level")+1)
1