Django(5)--model 2
Django-model(2)
模型查询
查询集表示从数据库获取的对象合集
查询集可以有多个过滤器
过滤器就是一个函数,基于所给的参数限制查询集结果
从SQL角度来说,查询集合和select语句等价,过滤器就像where条件
查询集和过滤器(queryset)
在管理器上调用方法返回查询集
查询经过过滤器筛选后返回新的查询集,所以可以写成链式调用
返回查询集的方法称为过滤器
all() 返回所有数据
filter() 返回符合条件的数据
exclude() 过滤掉符合条件的数据
order_by() 排序,默认根据ID排序,id大的在前-id
values() 一条数据就是一个字典,返回一个列表
def get_persions(request):
persion = Person.objects.all().order_by("-id")
persion = Person.objects.all().order_by("p_age")
context = {
"persion":persion,
}
return render(request,'persion_list.html',context=context)
def get_persions(request):
persion = Person.objects.all().order_by("p_age")
persion_values = persion.values()
print(type(persion_values),persion_values)
context = {
"persion":persion,
}
return render(request,'persion_list.html',context=context)
结果返回一个列表,列表中都是字典,方便以后转json:
<class 'django.db.models.query.QuerySet'> <QuerySet [{'id': 15, 'p_name': 'Tom8', 'p_age': 13, 'p_sex': True, 'p_hobby': None}, {'id': 22, 'p_name': '小明', 'p_age': 15
, 'p_sex': True, 'p_hobby': None}, {'id': 3, 'p_name': 'Tom16', 'p_age': 16, 'p_sex': False, 'p_hobby': None}, {'id': 19, 'p_name': 'Tom12', 'p_age': 19, 'p_sex': True,
'p_hobby': None}, {'id': 11, 'p_name': 'Tom4', 'p_age': 27, 'p_sex': True, 'p_hobby': None}, {'id': 10, 'p_name': 'Tom3', 'p_age': 30, 'p_sex': False, 'p_hobby': None}
, {'id': 7, 'p_name': 'Tom0', 'p_age': 42, 'p_sex': False, 'p_hobby': None}, {'id': 14, 'p_name': 'Tom7', 'p_age': 42, 'p_sex': False, 'p_hobby': None}, {'id': 9, 'p_na
me': 'Tom2', 'p_age': 43, 'p_sex': True, 'p_hobby': None}, {'id': 18, 'p_name': 'Tom11', 'p_age': 47, 'p_sex': True, 'p_hobby': None}, {'id': 16, 'p_name': 'Tom9', 'p_a
ge': 48, 'p_sex': False, 'p_hobby': None}, {'id': 4, 'p_name': 'Tom49', 'p_age': 49, 'p_sex': True, 'p_hobby': None}, {'id': 21, 'p_name': 'Tom14', 'p_age': 49, 'p_sex'
: True, 'p_hobby': None}, {'id': 8, 'p_name': 'Tom1', 'p_age': 60, 'p_sex': False, 'p_hobby': None}, {'id': 13, 'p_name': 'Tom6', 'p_age': 61, 'p_sex': True, 'p_hobby':
None}, {'id': 2, 'p_name': 'Tom62', 'p_age': 62, 'p_sex': False, 'p_hobby': None}, {'id': 1, 'p_name': 'Tom69', 'p_age': 69, 'p_sex': True, 'p_hobby': None}, {'id': 12
, 'p_name': 'Tom5', 'p_age': 70, 'p_sex': False, 'p_hobby': None}, {'id': 17, 'p_name': 'Tom10', 'p_age': 74, 'p_sex': False, 'p_hobby': None}, {'id': 5, 'p_name': 'Tom
79', 'p_age': 79, 'p_sex': True, 'p_hobby': None}, '...(remaining elements truncated)...']>
def get_persions(request):
persion = Person.objects.all().order_by("p_age")
persion_values = persion.values()
print(type(persion_values),persion_values)
for persion_value in persion_values:
print(persion_value)
context = {
"persion":persion,
}
return render(request,'persion_list.html',context=context)
结果:
{'id': 15, 'p_name': 'Tom8', 'p_age': 13, 'p_sex': True, 'p_hobby': None}
{'id': 22, 'p_name': '小明', 'p_age': 15, 'p_sex': True, 'p_hobby': None}
{'id': 3, 'p_name': 'Tom16', 'p_age': 16, 'p_sex': False, 'p_hobby': None}
{'id': 19, 'p_name': 'Tom12', 'p_age': 19, 'p_sex': True, 'p_hobby': None}
{'id': 11, 'p_name': 'Tom4', 'p_age': 27, 'p_sex': True, 'p_hobby': None}
返回单个数据
get():返回一个满足条件的对象(要注意)
如果没有找到符合条件的对象,会引发模型类.DoesNotExist异常,如果找到多个,会引发模型类.MultiObjectsResturned异常
first():返回查询集中的第一个对象
last():返回查询集中的最后一个对象
count():返回当前查询集中的对象个数
exists():判断查询集中是否有数据,如果有数据返回True没有反之
状态码(扩展)
- 2xx
- 请求成功
- 3xx
- 转发或重定向
- 4xx
- 客户端错误
- 5xx
- 服务器错了
- 后端开发人员最不想看到的
获取单个对象(get)
- 查询条件没有匹配的对象,会抛异常,DoesNotExist
- 如果查询条件对应多个对象,会抛异常,MultipleObjectsReturned
from django.conf.urls import url
from App import views
urlpatterns = [
url(r'^addpersions/',views.add_persions),
url(r'getpersions/',views.get_persions),
url(r'^addperson',views.add_person),
url(r'^getperson/',views.get_person),
]
def get_person(request):
#person = Person.objects.get(p_age=66)
#如果有两个47
person = Person.objects.get(p_age=47)
print(person)
return HttpResponse("获取成功")
first和last
- 默认情况下可以正常从queryset中获取
- 隐藏bug,可能会出现first和last获取到的是相同的对象
- f方法:显示,手动写排序规则
def get_person(request):
#第一个人
person = Person.objects.all().first()
print(person.p_name)
# 最后一个人
person_one = Person.objects.all().last()
print(person_one.p_name)
return HttpResponse("获取成功")
新建startApp Two
from django.conf.urls import url
from Two import views
urlpatterns = [
url(r'^getuser',views.get_user),
]
from django.db import models
# Create your models here.
class User(models.Model):
u_name = models.CharField(max_length=16,unique=True)
u_password = models.CharField(max_length=256)
def get_user(request):
username = "Sunck"
password = "120"
users = User.objects.filter(u_name = username)
print(users.count())
if users.count():
user = users.first()
if user.u_password == password:
print('获取用户信息成功')
else:
print('密码错误')
else:
print('用户不存在')
return HttpResponse('获取成功')
- count判断
def get_user(request):
username = "dd"
password = "120"
users = User.objects.filter(u_name = username)
print(users.count())
if users.count():
user = users.first()
if user.u_password == password:
print('获取用户信息成功')
else:
print('密码错误')
else:
print('用户不存在')
return HttpResponse('获取成功')
结果:
Quit the server with CTRL-BREAK.
0
用户不存在
[02/Dec/2019 16:50:32] "GET /Two/getuser HTTP/1.1" 200 12
def get_user(request):
username = "Sunck"
password = "1234"
users = User.objects.filter(u_name = username)
print(users.count())
if users.count():
user = users.first()
if user.u_password == password:
print('获取用户信息成功')
else:
print('密码错误')
else:
print('用户不存在')
return HttpResponse('获取成功')
结果:
Quit the server with CTRL-BREAK.
1
密码错误
[02/Dec/2019 16:51:45] "GET /Two/getuser HTTP/1.1" 200 12
- exists 直接判断
def get_user(request):
username = "Sunck"
password = "120"
user = User.objects.filter(u_name = username)
print(user.count())
if user.count():
user = users.first()
if user.u_password == password:
print('获取用户信息成功')
else:
print('密码错误')
else:
print('用户不存在')
return HttpResponse('获取成功')
结果:
Quit the server with CTRL-BREAK.
1
密码错误
[02/Dec/2019 16:54:54] "GET /Two/getuser HTTP/1.1" 200 12
限制查询集和查询集的缓存
限制查询集,可以使用下标的方法进行限制,等同于SQL中的limit
studentlist = student.objects.all()[0:5] 下标不能是负数
查询集的缓存:每个查询集都包含一个缓存,来最小化对数据库的访问
在新建的查询集中,缓存首次为空,第一次对查询集求值,会发生数据缓存,Django会将查询出来的数据做一个缓存,并返回查询结构,以后的查询直接使用查询集的缓存。
切片
- 和python中的切片不太一样
- queryset[5:15] 获取第5条到第15条数据
- 相当于SQL语句中的limit和offset
缓存集
- filter
- exclude
- all
- 都不会真正的去查询数据库
- 只有我们在迭代结果集,或者获取单个对象属性的时候,它才会去查询数据库
- 懒查询
- 为了优化我们的结构和查询
from django.conf.urls import url
from Two import views
urlpatterns = [
url(r'^getuser/',views.get_user),
url(r'^getusers/',views.get_users),
]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Userlist</title>
</head>
<body>
<h3>Userlist</h3>
<hr>
<ul>
{% for users in users %}
<li>姓名:{{ users.u_name }}</li>
{% endfor %}
</ul>
</body>
</html>
def get_users(request):
users = User.objects.all()[1:3] #左闭右开
# print(users)
context = {
"users":users
}
return render(request,'users_list.html',context=context)
字段查询
对sql中where的实现,作为方法filter(),exclude(),get()的参数
语法:属性名称__比较运算符=值
外键:属性名_id
转义:like语句中使用%是为了匹配占位符,匹配数据中的%(where like '%')
filter(sname__contains='%')
查询条件(比较运算符)
- 属性__运算符=值
- exact:判断,大小写敏感,filter(isDelete = False)
- contains 类似于模糊查询 like,是否包含,大小写敏感,filter(sname__contains='王')
- startwith 以xx开始 本质也是like,以values开头或结尾,大小写敏感
- endwith 以xx结束,本质也是like
以上4个在运算符前加上 i(ignore)忽略就不区分大小写了 iexact...
-
isnull,isnotnull:是否为空,filter(sname__isnull=False)
-
in 在某个集合中,是否包含在范围内,filter(pk__in=[2,5,6])
-
gt,gte,lt,lte:大于,大于等于,小于,小于等于 filter(sage__gt=30)
时间的:
-
year,month,day,week_day,hour,minute,second:
-
filter(lasttime__year=2017)
-
Django中查询条件有时区问题
-
关闭Django中自定义的时区
- settings.py
USE_TZ = False
-
在数据库中创建对应的时区表
-
-
models.py 验证时间属性
class Order(models.Model):
o_num = models.CharField(max_length=16,unique=True)
#auto_now_add自动加时间
o_time = models.DateTimeField(auto_now_add=True)
G:\py27\Django_project\DjangoModel>python manage.py shell
Python 3.7.0 (v3.7.0:1bf9cc5093, Jun 27 2018, 04:59:51) [MSC v.1914 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from Two.models import Order
>>> order = Order()
>>> order.o_num = '110'
>>> order.save()
>>> order = Order()
>>> order.o_num = '120'
>>> order.save()
>>> order = Order()
>>> order.o_num = '111'
>>> order.save()
Two/urls.py
from django.conf.urls import url
from Two import views
urlpatterns = [
url(r'^getorder/',views.get_orders),
]
from django.shortcuts import render,HttpResponse
from Two.models import Order
# Create your views here.
def get_orders(request):
orders = Order.objects.filter(o_time__year=2020)
for order in orders:
print(order.o_num)
return HttpResponse('获取成功')
def get_orders(request):
# month月份不会打印数据是时区问题,在settings.py中关闭时区就可以打印了
orders = Order.objects.filter(o_time__month=12)
for order in orders:
print(order.o_num)
return HttpResponse('获取成功')
查询快捷:
- pk:代表主键,filter(pk=1)
跨关系查询:
- 模型类名__属性名__比较运算符,实际上就是处理的数据库中的join
- grade = Grade.objects.filter(stduent__sconted__contains='晓强')
- 描述中带有'晓强'这两个字的数据属于哪个班级
直接根据学生的信息查询班级
class Grade(models.Model):
g_name = models.CharField(max_length=16)
class Student(models.Model):
s_name = models.CharField(max_length=16)
s_grade = models.ForeignKey(Grade)
from django.conf.urls import url
from Two import views
urlpatterns = [
#url(r'^getuser/',views.get_user),
#url(r'^getusers/',views.get_users),
url(r'getgrades/',views.get_grades),
]
def get_grades(request):
#根据级联数据的信息查询,跨关系查询
grades = Grade.objects.filter(student__s_name = 'Jack')
for grade in grades:
print(grade.g_name)
return HttpResponse('获取成功')
聚合函数
使用 aggregate()函数返回聚合函数的值
- Avg:平均值
- Count:数量
- Max:最大值
- Min:最小值
- Sum:求和
student.objects().aggregate(max('sage'))
class Customer(models.Model):
c_name = models.CharField(max_length=16)
c_cost = models.IntegerField(default=10)
E:\py27\Django_project\djangomodel>python manage.py shell
Python 3.7.4 (tags/v3.7.4:e09359112e, Jul 8 2019, 20:34:20) [MSC v.1916 64 bit (AMD64)] on win
32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from Two.models import Customer
>>> for i in range(10):
... customer = Customer()
... customer.c_cost = i
... customer.c_name = "C%d" %i
... customer.save()
...
>>> exit()
def get_customer(request):
#Max要倒包,Djangodb中的
ret = Customer.objects.aggregate(Max('c_cost'))
#ret = Customer.objects.aggregate(Avg('c_cost')) #获取平均
print(ret)
return HttpResponse('花费成功')
F对象
-
可以获取我们属性的值
-
可以实现一个模型的不同属性的运算操作
-
还可以支持算数运算
-
可以使用模型的A属性与B属性进行比较
-
grades = Grade.objects.filter(ggirlnum__gt=F('gboynum'))
-
F对象支持算数运算符
grades = Grade.objects.filter(ggirlnum__gt=F('gboynum')+10)
class Conpany(models.Model):
c_name = models.CharField(max_length=16)
c_gril_num = models.IntegerField(default=5)
c_boy_num = models.IntegerField(default=3)
from django.conf.urls import url
from Two import views
urlpatterns = [
# url(r'^getuser/',views.get_user),
# url(r'^getusers/',views.get_users),
# url(r'getgrades/',views.get_grades),
# url(r'getcustomer/',views.get_customer),
url(r'getconpany',views.get_conpany),
from django.db.models import Max, Avg, F, Q
def get_conpany(request):
#男生比女生少
#conpays = Conpany.objects.filter(c_boy_name__lt=F('c_gril_num'))
#女生比男生多15以上
conpays = Conpany.objects.filter(c_boy_name__lt=F('c_gril_num')-15)
for conpay in conpays:
print(conpay.c_name)
return HttpResponse("获取公司成功")
Q对象
- 条件封装
- 可以对条件进行封装
- 封装之后,可以支持逻辑运算(与、或、非)
- 过滤器的方法中的关键字参数,常用于组合条件
- 年龄小于25
- Student.objects.filter(Q(sage__lt=25))
- Q对象语法支持| (or),&(and),~(取反)
- 年龄大于等于的
- Student.objects.filter(~Q(sage__lt=25))
from django.db.models import Max, Avg, F, Q
def get_conpany(request):
# conpays = Conpany.objects.filter(c_boy_name__gt=1).filter(c_gril_num=5)
# conpays = Conpany.objects.filter(Q(c_boy_name__gt=1) & Q(c_gril_num__gt=5))
conpays = Conpany.objects.filter(Q(c_boy_name__gt=1) | Q(c_gril_num__gt=5))
for conpay in conpays:
print(conpay.c_name)
return HttpResponse("获取公司成功")
模型成员
-
类属性
- 显性:开发者自己写的那些
- 隐形:objects是一个Manager类型的一个对象,作用于数据库进行交互(开发者没有书写,orm自动生成)
- 如果你把隐形属性手动声明了,系统就不会为你产生隐形属性了
-
当模型类没有指定管理器的时候,Djang会自动为我们创建模型管理器
-
当然我们也可以自定义管理器,
class Student(models.Model): stuManager = models.Manager()
-
当自定义模型管理器时,objects就不存在了,Django就不会为我们自动生成模型管理器
-
class Animal(models.Model):
a_name = models.CharField(max_length=16)
from django.conf.urls import url
from Two import views
urlpatterns = [
# url(r'^getuser/',views.get_user),
# url(r'^getusers/',views.get_users),
# url(r'getgrades/',views.get_grades),
# url(r'getcustomer/',views.get_customer),
#url(r'getconpany',views.get_conpany),
url(r'getanimals/',views.get_animals),
def get_animals(request):
animals = Animal.objects.all()
for animal in animals:
print(animal.a_name)
return HttpResponse('动物获取成功')
- 隐性变显性
class Animal(models.Model):
a_name = models.CharField(max_length=16)
a_m = models.Manager()
def get_animals(request):
animals = Animal.a_m.all()
for animal in animals:
print(animal.a_name)
return HttpResponse('动物获取成功')
class Animal(models.Model):
a_name = models.CharField(max_length=16)
#is_delete是否删除,重要的数据做逻辑删除
is_delete = models.BooleanField(default=False)
a_m = models.Manager()
# 加属性要迁移数据库
python manage.py makemigrations
python manage.py migrate
- 删了狗
def get_animals(request):
animals = Animal.a_m.filter(is_delete = False)
for animal in animals:
print(animal.a_name)
return HttpResponse('动物获取成功')
# 查不到狗了
自定义管理器类
模型管理器是Django的模型与数据库进行交互的接口,一个模型可以有多个模型管理器
自定义模型管理器作用:
- 可以向管理器中添加额外的方法
- 修改管理器返回的原始查询集
- 提供创建对象的方式
class StudentManager(models.Manager):
def get_queryset(self):
return
super(StudentManager,self).get_queryset.filter(isDelete=False)
def createStudent(self):
stu= self.mode()
#设置属性
return stu
class AnimalManager(models.Model):
def get_queryset(self):
return super(AnimalManager,self).get_queryset().filter(is_delete=False)
- 增量改属性
class Animal(models.Model):
a_name = models.CharField(max_length=16)
#is_delete是否删除,重要的数据做逻辑删除
is_delete = models.BooleanField(default=False)
objects = AnimalManager()
def get_animals(request):
animals = Animal.a_m.all()
animals = Animal.objects.all()
for animal in animals:
print(animal.a_name)
return HttpResponse("动物获取成功")
# 增加create方法
class AnimalManager(models.Model):
def get_queryset(self):
return super(AnimalManager,self).get_queryset().filter(is_delete=False)
def create_animal(self,a_name ="Chicken"):
a = self.model()
a.a_name = a_name
return a
def get_animals(request):
animals = Animal.a_m.all()
for animal in animals:
print(animal.a_name)
Animal.objects.create_animal()#调用create方法
return HttpResponse("动物获取成功")
作业
- 做一个班级学生列表
- 班级列表
- 班级列表可点击
- 点击的时候显示班级所有学生