MVC:一种设计模式.就是把代码解耦,分割成很多部件
- M:模型(model):是应用程序中用于处理应用程序数据逻辑的部分.
通常模型对象负责在数据库中存取数据 - V:视图(View):是应用程序中处理数据显示的部分.
通常视图是依据模型数据创建的. - C:控制器(Controller):是应用程序中处理用户交互的部分.
通常控制器负责从视图读取数据,控制用户输入,并向模型发生数据
示例:
用户(就是上面的电脑)发送一个HTTP请求给服务器,背后的逻辑是:
- 控制器接受用户的request
- 控制器让model去数据库里拿数据,然后将数据发给控制器.
- 然后控制器将拿到的数据发送给视图.
- 最后视图将拿到的数据显示给用户
Django将MVC模式修改成MTV模式:
- Model:模型:负责业务对象与数据库对象(ORM)
和MVC的Model差不多,还是负责管理数据的. - Template:模板:负责如何把页面展示给用户.
相当于MVC的View,负责展示页面 - View:视图:负责业务逻辑,并在适当的时候调用Model和Template.
相当于MVC的Controller
注意:Django还有一个url分发器,作用是将一个个的url页面请求分发给不同的view处理,view再调用相应的Model和VTemplate
示例:
用户发送一个request请求
- url分发器根据url将不同的请求分给不同的view.
- view告诉模型将数据库的数据拿出来给View
- view再将从模型拿到的数据给模板,让模板展示给用户.
项目说明:
- manage.py:一个命令行工具,可以使我们使用多种方式对Django项目进行交互
- _init_.py:空文件,他告诉python这个目录应该被看作一个python包
- setting.py:项目的配置文件
- urls.py:项目的url声明(就是url分发器)
- wsgi.py:项目与wsgi兼容的web服务器入口.
基本操作:
设计表结构
配置数据库:
因为Django默认数据为SQLite,我们可以将其修改为MySQL.在setting.py的DATABASES选项配置:1
2
3
4
5
6
7
8DATABASES = {
'default': {
# 使用的数据库类型
'ENGINE': 'django.db.backends.sqlite3',
# 使用数据库的名
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}修改步骤如下:
在_init_.py写入:
1
2import pymysql
pymysql.install_as_MySQLdb()首先在MySQL里创建一个数据库:(数据库名自选)
1
create database djangoDB;
将setting.py的DATABASES选项配置改为:
1
2
3
4
5
6
7
8
9
10DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'djangoDB',
'USER':'root',
'PASSWORD':'5KVp2y7,k96o',
'HOST':'localhost',
'POST':'3306'
}
}
创建应用:
在一个项目中可以创建多种应用.每个应用运行一种业务处理.1
2# 注意在manage.py中运行
python manage.py startapp myappadmin.py:站点配置
models.py:模型:
view.py:视图
注意在创建应用之后需要激活应用:
在setting.py中,将myapp应用加入到installed_apps中
定义模型:
模型其实就是一个类.这个类继承model.Model1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23from django.db import models
# Create your models here.
class Grades(models.Model):
gname = models.CharField(max_length=20)
gdate = models.DateTimeField()
ggirlnum = models.IntegerField()
gboynum = models.IntegerField()
isDelete = models.BooleanField()
def __str__(self):
return f'{gname}-{gdate}'
class Students(models.Model):
sname =models.CharField(max_length=20)
sgender = models.BooleanField(default=True)
sage = models.IntegerField()
scontend = models.CharField(max_length=20)
# 定义外键
sgreade = models.ForeignKey('Grades')
isDelete = models.BooleanField(default=False)
def __str__(self):
return f'{sname}-{sdate}'在数据库中生成数据表:
生成迁移文件
1
python manage.py makemigrations
这时就会在migrations目录下生成迁移文件.
(此时数据库中还没有生成数据表)1
2
3
4
5
6
7
8
9# 在数据库中键入
show tables;
/*
+--------------------+
| Tables_in_djangodb |
+--------------------+
| django_migrations |
+--------------------+
*/执行迁移
1
python manage.py migrate
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34# 在数据库中键入
show tables;
/*
+----------------------------+
| Tables_in_djangodb |
+----------------------------+
| auth_group |
| auth_group_permissions |
| auth_permission |
| auth_user |
| auth_user_groups |
| auth_user_user_permissions |
| django_admin_log |
| django_content_type |
| django_migrations |
| django_session |
| myapp_grades |
| myapp_students |
+----------------------------+
*/
desc myapp_grades;
/*
+----------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| gname | varchar(20) | NO | | NULL | |
| gdate | datetime(6) | NO | | NULL | |
| ggirlnum | int(11) | NO | | NULL | |
| gboynum | int(11) | NO | | NULL | |
| isDelete | tinyint(1) | NO | | NULL | |
+----------+-------------+------+-----+---------+----------------+
*/
数据操作:
进入到python shell
1
python manage.py shell
引入包:
1
2
3from myapp.models import Grades,Students
from django.utils import timezone
from datetime import *查询所有数据
1
2Grades.objects.all()
# <QuerySet []>添加数据:
本质:创建一个模型类的对象实例.1
2
3
4
5
6
7
8grade = Grades()
grade.gdate =datetime(year=2017,month=7,day = 7)
grade.gname = 'hyl'
grade.ggirlnum = 3
grade.gboynum = 70
grade.isDelete = False
grade.save()查询某个对象
1
2Grades.objects.get(id=1)
# <Grades: Grades object>修改数据:
1
2
3x = Grades.objects.get(id=1)
x.gname = 'hyl'
x.save()删除数据:
1
Grades.objects.get(id=1).delete()
连接关联对象:
使用模式创建外键的方式:把另一个表的实例对象作为这个表实例对象的属性1
2
3
4s1 = Students()
g1 = Grades()
# 把另一个表的实例对象作为这个表实例对象的属性
s1.sgreade = g1获取关联对象:
属性:关联的类名(小写)_set1
2
3
4# 一对多,一实体具有一个自带的属性
# 这个属性名为:多实体表名_set
g1 = Grades()
g1.students_set.all()便捷的添加表数据的方式:
关联的类名(小写)_set.create1
2# 使用班级表的实例对象来创建学生数据
g1.students_set.create(sname='hyl',sgender=True,scontend='my name is hyl',sage=45)
启动服务器:
1
python manage.py runserver ip:port
ip可以不写,不写的话代码本机IP,端口号默认8000
说明:这是一个纯python写的轻量级web服务器,仅仅在开发测试中使用
Admin站点管理:
概述:
- 内容发布:负责添加,修改,删除内容.
(这是真正意义就修改数据库中数据,只是提供一个可视化界面而已) - 公告访问
- 内容发布:负责添加,修改,删除内容.
配置Admin应用:
admin其实本身就是一个应用.要使用这个应用就需要在setting.py中配置.(当然默认已经配置好了)1
2
3
4
5INSTALLED_APPS = [
# 默认配置好了
'django.contrib.admin',
...
]创建管理员用户:
1
python manage.py createsuperuser
然后进入127.0.0.1:8000/admin即可
汉化:
1
2LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/shanghai'管理数据表:
修改admin文件1
2
3
4
5
6
7# myapp/admin
# 先导入
from .models import Grades,Students
# 后注册
admin.site.register(Grades)
admin.site.register(Students)自定义管理页面
使用管理页面类1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24# Register your models here.
from django.contrib import admin
# 先导入表格类
from .models import Grades,Students
class GradesAdmin(admin.ModelAdmin):
# 列表页属性
list_display = ['id','gname','gdate','ggirlnum','gboynum','isDelete']
list_filter = ['gname']
search_fields = ['gname']
list_per_page = 5
# 添加,修改页面属性
# fileds和fieldsets不能同时使用
# fields = ['ggirlnum','gboynum','gname','gdate','isDelete']
fieldsets = [
('num',{'fields':['ggirlnum','gboynum']}),
('base',{'fields':['gname','gdate','isDelete']}),
]
# 后注册表格类(要导入GradesAdmin类作为参数)
admin.site.register(Grades,GradesAdmin)
admin.site.register(Students)列表页属性
list_display:
1
list_display = ['id','gname','gdate','ggirlnum','gboynum','isDelete']
显示需要的字段
list_filter:
过滤字段(就是添加一个过滤器)1
list_filter = ['gname']
search_fields:
添加一个搜索字段1
search_fields = ['gname']
list_per_page:
分页1
2# 每5条一页
list_per_page = 5
添加,修改页面属性
fields:
规定属性的顺序1
fields = ['ggirlnum','gboynum','gname','gdate','isDelete']
fieldsets:
给属性分组
注意fieldsets属性不能和fields属性同时使用1
2
3
4
5# 注意下面图片的字段顺序和这里的字段顺序是一致的
fieldsets = [
('num',{'fields':['ggirlnum','gboynum']}),
('base',{'fields':['gname','gdate','isDelete']}),
]
解释:为什么fieldsets和fields不能同时使用?因为fieldsets本身就已经对字段排序了.
关联对象:
需求:在创建一个班级时可以直接添加几个学生
这时还是要创建一个类StudentsInfo:1
2
3
4
5
6
7
8
9
10
11
12# 新建一个类
# 注意继承TabularInline
class StudentsInfo(admin.TabularInline):
# 要调用的表
model = Students
# 要添加几个数据
extra = 2
class StudentsInfo(admin.ModelAdmin):
# 将新建的类放在inlines里面
inlines = [StudentsInfo]
list_display = ...当新建一张Grade表的时候,下面就会提供一个Students让你填写:
其实StudentsInfo类不一定要继承admin.TabularInline,也可以继承admin.StackedInline,只是显示不同而已布尔值显示问题:
我们对于性别sgender使用了布尔值,但是在终端显示的是0,1.现在想要让他显示’男’和’女’
在类里定义方法,然后传入list_display1
2
3
4
5
6
7
8
9
10class StudentAdmin(admin.ModelAdmin):
# 定义一个方法
def gender(self):
if self.sgender:
return '男'
else:
return '女'
# 将方法gender代替掉原来的'sgender'
list_display = ['id','sname','sage',gender,'scontend','sgreade','isDelete']
list_per_page = 2修改字段名就是修改字段的short_description属性:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15class StudentAdmin(admin.ModelAdmin):
def gender(self):
if self.sgender:
return '男'
else:
return '女'
def sage(self):
return self
# 修改字段的字段名
# 修改字段的short_description属性
gender.short_description = '性别'
sage.short_description = '年龄'
# 替换字段
list_display = ['id','sname',sage,gender,'scontend','sgreade','isDelete']执行动作的位置问题
就是将这个框移动到下面去:
修改actions_on_top/actions_on_bottom属性:1
2
3
4
5
6class StudentAdmin(admin.ModelAdmin):
# 两个都是True则上下都有
actions_on_top = False
actions_on_bottom = True
...
使用装饰器完成注册admin.
我们上面将数据表注册到admin使用的方式是:
新建一个类StudentAdmin,然后通过修改这个类的属性来修改数据表的显示问题,最后将这个类使用1
admin.site.register(Grades,GradesAdmin)
来完成注册.
现在我们通过装饰器来完成注册:
其实方法很简单,就是将admin.site.register(Grades,GradesAdmin)
换成装饰器:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20# 使用装饰器,传入表格类作为参数
class StudentAdmin(admin.ModelAdmin):
actions_on_top = False
actions_on_bottom = True
def gender(self):
if self.sgender:
return '男'
else:
return '女'
def sage(self):
return self
# 修改字段的字段名
gender.short_description = '性别'
sage.short_description = '年龄'
list_display = ['id','sname',sage,gender,'scontend','sgreade','isDelete']
list_per_page = 2视图的基本使用:
概述:在Django中,视图对web请求进行回应
视图其实就是一个函数,在view.py中定义
url分发器来找到对应url,然后让这个url调用对应的视图.所以有多少个页面就有多少个视图.1
2
3
4
5
6# Create your views here.
from django.shortcuts import render
from django.http import HttpResponse
def index(request):
return HttpResponse('hello world')配置url:
修改project目录下的urls.py文件
1
2
3
4
5
6
7
8# project/urls.py
from django.conf.urls import url,include
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^',include('myapp.urls'))
]在myApp应用目录下创建一个urls.py文件
1
2
3
4
5
6
7
8# myapp/urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index),
]
流程说明:
- url控制器就是project目录下的urls.py.
- 当然我们键入http://127.0.0.1:8000/时,首先经过url控制器,匹配到`url(r'^',include('myapp.urls'))`
- 然后include视图函数定位到app.urls文件
- 进入app.urls后被
url(r'^$', views.index)
匹配 - 调用view.index函数
为什么要用两级的urls控制器?
project/urls.py是总的urls控制器,是不可或缺的.而myapp/urls.py是一个app应用的借口,只要调用了这个接口就可以使用这个app应用了,这有利于代码的重用.具体是如何重用的?
两级urls控制器是url的二级目录
eg:当我们输入http://127.0.0.1:8000/时调用总的urls控制器,匹配到`url(r'^',include('myapp.urls'))`,然后转到app.urls,匹配到`url(r’^$’, views.index)`,最后去调用view.index
如果我们输入http://127.0.0.1:8000/2怎么办?这时我们就可以在app.urls增加一个url.用来分类这个链接.1
2
3
4
5
6
7
8# project/urls.py
from django.conf.urls import url,include
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^',include('myapp.urls'))
]1
2
3
4
5
6
7
8
9
10
11# myapp/urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index),
# 注意是(\d+),要用分组
# 这个分组会传递给view.detail作为参数
url(r'^(\d+)/$',views.detail)
]1
2
3
4
5
6
7
8
9# myapp.views.py
from django.shortcuts import render
from django.http import HttpResponse
def index(request):
return HttpResponse('hello world')
def detail(request,num):
return HttpResponse(f'detail {num}')- 当我们输入http://127.0.0.1:8000/2时,首先到总的urls控制器中,
- 其中的
url(r'^',include('myapp.urls'))
匹配成功http://127.0.0.1:8000/
,然后调用对应的视图函数include('myapp.urls')
, include('myapp.urls')
调用app.urls,其中的url(r'^(\d+)/$',views.detail)
成功匹配到http://127.0.0.1:8000/2中的`/2`,调用视图函数views.detail- views.detail获取到
/2
,将其赋给num变量,返回 detail 2
总结:
也就是说,project/urls.py是用来匹配http://127.0.0.1:8000/的,而app.urls是用来匹配后面的/2的.==两级urls控制器是url的二级目录,用来层层细化url,最终找到对应的视图函数==
模板的基本使用:
概述:
模板是HTML页面,可以根据视图中传递过来的数据进行填充.创建模板:
在manage.py目录下创建一个对应模板目录templates.目录templates下面就存放每个app对应的模板文件配置模板目录:
修改setting.py文件的TEMPLATES选项.把templates的目录层级告诉DIRS变量1
2
3
4
5
6TEMPLATES = [
{
'BACKEND':...
'DIRS': [os.path.join(BASE_DIR,'templates')],
...
}基本使用:
目标:输入http://127.0.0.1:8000/grade返回数据库中grede表的内容.输入http://127.0.0.1:8000/student 返回数据库中student表的内容.定义模板:
找templates/myapp/目录下创建一个grade.html文件1
2
3
4
5
6
7
8
9
10
11
12<!-- templates/myapp/grades.html -->
<html lang='cn'>
<head>
<meta charset="UTF-8">
<title>班级信息</title>
</head>
<body>
</body>
</html>同理创建student.html
模板语法:
{{输出值,可以是变量,一个可以是对象属性}}
{%执行代码段%}
所以前面templates/myapp/grades.html修改为
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20<!-- templates/myapp/grades.html -->
<html lang='cn'>
<head>
<meta charset="UTF-8">
<title>班级信息</title>
</head>
<body>
<h1>班级信息列表</h1>
<!-- 每个班级,因此需要循环 -->
{%for grade in grades%}
<li>
<!-- 双括号下面可以是变量也可以是属性 -->
<a href="#">{{grade.gname}}</a>
</li>
{%endfor%}
</body>
</html>解释:
12行-17行其实是一个循环.表示遍历grades(这个grades会由views.py传入),每个grade创建一个<li>,<li>里面创建一个<a>,用grade.gname来填充数据.
修改myapp/urls.py
1
2
3
4
5
6
7
8
9from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index),
url(r'^(\d+)/$',views.detail),
# 匹配这个url
url(r'^grades/$',views.grades)
]创建视图函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15# myapp/views.py
from .models import Grades
def grades(request):
# grades函数的使命:去数据库里取出数据,将数据传递给模板
# (模板再渲染页面,将渲染好的页面返回给浏览器)
# 首先取出数据
gradeslist = Grades.objects.all()
# render的使用接口:
# 将某个数据数据传给myapp/grades.html这个模板,
# 是什么数据?实际上是一个字典
# 该字典以myapp/grades.html里使用的变量作为键,以数据表的数据作为值
return render(request,'myapp/grades.html',{'grades':gradeslist})结果如下:
模板的进阶使用:
现在我们已经创建一个班级信息列表了,现在我们需要制作下面功能,点击grade1,然后跳转到grade1的全部数据
(简单来说就是:点击班级显示对应班级的学生)首先我们将grade.html修改为:
1
2
3
4
5
6
7
8
9
10
11
12
13...
<body>
<h1>班级信息列表</h1>
<ul>
{%for grade in grades%}
<li>
# a标签的href修改为grade.id
<a href="{{grade.id">{{grade.gname}}</a>
</li>
{%endfor%}
</ul>
</body>这样,当我们点击的时候就会出现:
注意此时url已经变成了http://127.0.0.1:8000/grades/2,所以我们只需再制作一个url分发器,视图即可.1
2
3
4
5
6
7
8
9
10
11
12
13# app/urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index),
url(r'^(\d+)/$',views.detail),
url(r'^grades/$',views.grades),
url(r'^students/$',views.students),
# 添加新的url
url(r'^grades/(\d+)$',views.detail_grades)
]1
2
3
4
5
6
7
8# app/views.py
# 注意这里的视图函数多了一个num参数(从url分发器里拿到的)
def detail_grades(request,num):
grade = Grades.objects.get(id=num)
studentslist = grade.students_set.all()
# 重要:注意这里还是调用了student.html这个模板(并没有新建模板)
return render(request,'myapp/students.html',{'students':studentslist})
简要流程:
- 创建工程:
django-admin startproject myproject - 创建项目:
python manage.py startapp myapp - 激活项目:
修改setting.py中的INSTALLED_APPS - 配置数据库:
- 修改__init__.py文件
- 修改setting.py中的DATABASES
- 创建模型类:
在项目目录下的models.py文件中 - 生成迁移文件:
python manage.py makemigrations - 执行迁移:
python manage.py migrate - 配置站点
- 创建template目录/项目模板目录
- 在setting.py中配合模板路径
- 在project下修改urls.py
- 在项目目录下创建urls.py
当我们获取一个Django项目时,如果才能在我们的电脑里运行?
- 在setting.py里修改数据库名,数据库密码
- 删除迁移文件
- 在数据库中创建对应的数据库
- 执行生成迁移文件
- 执行迁移
模型
Django对各种数据库都有很好的支持,而且提供了统一的API接口
ORM:
O:对象,R:关系,M:映射
任务:
- 根据对象的类型生成表结构
- 将对象,列表的操作转换为sql语句
- 将sql语句查询到的结果转换为对象和列表
优点:极大的减轻了开发人员的工作量,不需要面对因数据库的变更和修改代码.
定义模型:
模型,属性,表,字段的关系:- 模型类在数据库中对应一张表
- 在模型类中定义的属性对应该模型对照表中得到一个字段.
定义属性:
- django会为表添加自动增长的主键列,每个模型只能有一个主键列.
但是如果使用选项设置某属性为主键列后,则就不能生成默认的主键列 - 属性命名规则:
不能用python的关键字.
不能使用连续的下划线. - 所有的字段类型都被定义在django.db.models.fields目录下
- ==强烈建议对于重要的数据做逻辑删除,而不是物理删除==
实现方法是定义isDelete属性,类型为BooleanField,默认值为False
- django会为表添加自动增长的主键列,每个模型只能有一个主键列.
字段类型:
AutoField:
实际上默认的主键列的字段类型就是AutoField.他是一个会根据实际ID自动增长的IntegerField,通常不用这个字段类型.CharField(max_length=字符长度):
字符串类型.默认的表单样式是TextInput(就是在站点管理的时候显示的是textinput格式)TextField:
大文本字段.一般超过4000字节的时候使用.默认的表单控件是TextareaIntegerField:
整数字段DecimalField(max_digits=None,decimal_places=None):
使用python的Decimal实例表示的十进制浮点数.
DecimalFiled.max_digits:位数总数.
DecimalField.decimal_places:小数点后的数字位数.floatField:
用python的float实例来表示的浮点数.BooleanField:
布尔字段,默认表单控件是CheckboxInputNullBooleanField:
支持Null,true,false三种值.DateField([auto_now =False,auto_now_add =False]):
使用python的datetime.date实例表示的日期.默认对应的表单控件时候一个TextInput
DateField.auto_now:每次保存对象时,自动设置该字段为当前时间,一般用于最后一次修改
的时间戳(就是说,当修改一行的时候,该行的DateField字段就会指定更改时间)
DateField.auto_now_add:当对象第一次被创建时自动设置当前时间,用于创建的时间.戳,他总是使用当前日期
注意:auto_now_add和auto_now是互斥的.他们不会同时出现在同一个字段.(废话,一个是创建时间,一个是修改时间.)
TimeField([auto_now =False,auto_now_add =False]):
使用python的datetime.time实例表示的时间,参数同DateFieldDateTimeField([auto_now =False,auto_now_add =False]):
使用python的datetime.
datetime实例表示的日期和时间,参数同DateFieldFileField:
一个上传文件的字段.ImageField:
继承了FileField的所有属性和方法,但对上传的对象进行校验,确保这是一个有效的Image.
字段选项:
概述:
通过字段选项,可以实现对字段的约束.字段选项必须使用关键字参数.null:
将空值存储到数据库中,默认为Falseblanke:
如果为True,该字段允许空白.默认为False
注意null是数据库范畴的概念,blank是表单验证范畴的.
db_column:
字段的名称.如果未指定,这使用属性的名称.
eg:当我们定义一个字段时若写到:
sage = models.IntegerField(db_column='age')
则在数据库中回忆age来命名该字段,但是models.py中该字段的名称还是sage.db_index:
若为True,则会在表中以此字段创建索引.default:
默认值primary_key:
若为True,设置主键字段unique:
唯一约束.
关系:
- 分类:
- Foreignkey:一对多,将字段定义在==多==的端中
- ManyToManyField:多余多,将字段定义在==两端==中(本来按照数据库的完整性约束应该再手动建一张表的,但是Django已经帮我们建好了)
- OneToOneField:一对一,将字段定义在任意一端中.
- 用一访问多:
格式:对象.模型类小写_set
示例:grade.students_set
- 用一访问一:
格式:对象.模型类小写
示例:grade.students
- 访问id:
格式:对象.属性_id
示例:student.sgrade_id
- 分类:
元选项:
在模型类==里面==定义一个Meta类,用于设置元信息.- db_table:
修改默认的数据表名(默认为:项目名_类名
). - ordering:
返回结果时对数据自动排序
(字段名前面+号表示升序(可省略)ordering=['id']
,
-号表示降序ordering=['-id']
)
1
2
3
4
5
6
7
8
9
10
11
12
13class Students(models.Model):
sname =models.CharField(max_length=20)
sgender = models.BooleanField(default=True)
sage = models.IntegerField()
scontend = models.CharField(max_length=20)
sgreade = models.ForeignKey('Grades')
isDelete = models.BooleanField(default=False)
class Meta:
# 修改默认的数据表名
db_table='students'
# 返回结果时对数据自动排序
ordering=['id']- db_table:
模型成员:
类属性:
object:
是Manager类型
的一个对象,作用是与数据库进行交互.当定义模型类时没有指定管理器,则Django为模型创建一个名为objects的管理器.
自定义模型管理器.(会覆盖掉原来的objects模型管理器)
1
2
3
4
5class Students(models.Model):
# 自定义模型管理器
stuObj = models.Manager()
sname = ...此时就不能再使用students.objects了:
1
2
3
4
5# 报错
students.objects.all()
# 正确运行
student.stuObj.all()到目前为止,我们修改了模型管理器,但是没有什么鸟用,只是修改了名称而已.
自定义管理器Manager类:
==模型管理器是Django的模型与数据库进行交互的接口.==
一个模型可以有多个模型管理器1
2
3
4
5
6class Students(models.Model):
# 多个模型管理器
stuObj1 = models.Manager()
stuObj2 = models.Manager()
sname = ...自定义的模型管理器的作用:
可以管理器类中添加额外的方法.
比如说添加一个新方法让我们能更方便的在数据库中添加数据.1
2
3
4
5
6
7
8
9class Students(models.Model):
# 定义一个类方法,让我们能更方便的创建对象
def createStudent(cls,name,age,gender,contend,greade,isDelete=Flase):
stu = cls(sname=name,sage=age,sgender=gender,scontend=contend,sgreade=greade,isDelete=isDelete)
return stu
stuObj = StudentsManager()
sname = ...修改管理器返回的原始查询集.
比如说,我们可以通过改写get_queryset()方法,让student.objects.all()不返回isDelete为True的数据.1
2
3
4
5
6
7
8
9# 继承models.Manager
class StudentsManager(models.Manager):
def get_queryset(self):
return super(StudentManager,self).get_queryset().filter(isDelete=False)
class Students(models.Model):
# 自定义模型管理器,使用自定义的模型管理器
stuObj = StudentsManager()
sname = ...
创建对象:
目的:
向数据库中添加数据当创建对象时,Django不会对数据库进行读写操作,,当调用save方法时才会与数据库交互,将对象保存到数据库中.
注意:__init__方法已经在父类models.Model中使用,在自定义的模型中无法使用.
只能为模型表对象实例挨个添加属性,然后save()第三点的解决方法有两种:
在模型类中增加一个类方法.
1
2
3
4
5
6
7
8
9class Students(models.Model):
# 定义一个类方法,让我们能更方便的创建对象
def createrStudent(cls,name,age,gender,contend,greade,isDelete=Flase):
stu = cls(sname=name,sage=age,sgender=gender,scontend=contend,sgreade=greade,isDelete=isDelete)
return stu
stuObj = StudentsManager()
sname = ...在自定义管理器中添加一个方法.
1
2
3
4
5
6
7class StudentsManager(models.Manager):
def get_queryset(self):
return super(StudentManager,self).get_queryset().filter(isDelete=False)
# 定义这个方法后,就可以使用stu = Students.objects.createrStudent(...)
def createrStudent(self,name,age,gender,contend,greade,isDelete=Flase):
stu = cls(sname=name,sage=age,sgender=gender,scontend=contend,sgreade=greade,isDelete=isDelete)
return stu但是如果使用上面的方法,那么这个管理器就只能适用于Students,所以我们可以如下使用:
1
2
3
4
5
6
7
8
9
10
11
12
13class StudentsManager(models.Manager):
def get_queryset(self):
return super(StudentManager,self).get_queryset().filter(isDelete=False)
def createrStudent(self,name,age,gender,contend,greade,isDelete=Flase):
# 使用self.model(),表示使用该管理器对应的模型创建一个空的实例对象
stu = self.model()
stu.sage = age
stu.sname = name
stu.sgender = gender
stu.scontend = contend
stu.sgreade = greade
stu.isDelete = isDelete
return stu
模型查询:
概述:
- 查询集:表示从数据库中获取的对象的集合
(简单来说就是查询数据库里所有的数据) - 查询集可以有多个过滤器
- 过滤器就是一个函数,基于所给的参数限制查询的结果.
- 从SQL的角度来说,查询集和select语句等价
过滤函数就是where条件
- 查询集:表示从数据库中获取的对象的集合
查询集:
在管理器中调用过滤方法返回查询集
1
2
3class StudentsManager(models.Manager):
def get_queryset(self):
return super(StudentManager,self).get_queryset().filter(isDelete=False)查询集经过过滤器筛选后返回新的查询集.
所以我们可以写成链式调用.惰性执行:
创建查询集不会带来任何数据库的访问,直到调用数据时,才会访问数据库.直接访问数据的情况:
- 迭代
- 序列化
- 与if合用
返回查询集的方法称为过滤器:
all():
返回查询集中的所有值filter():
返回符合条件的值filter(键1=值1,键2=值2):
且
的关系,就是说,要同时符合两种exclude:
过滤到符合条件的数据.order_by():
和MySQL一样,用于排序values():
其实数据库的一条数据就是一个字典,多个字典组成一个列表.values()就是将这个列表返回.values()和all()的区别:
我们之前说过all()返回的是一个QuerySet,QuerySet就是一个类似于列表的对象.
values()返回的是一个真正的列表,列表元素是字典(一个字典就是一条数据)
返回单个数据:
get():
返回一个满足条件的对象注意:
如果没有符合条件的对象,模型类会引发DoseNotExist异常.
如果找到多条数据,会引发MutlipleObjectsReturned异常.count():
返回当前查询集的对象个数find():
返回查询集中的第一个对象last():
返回查询集中的最后一个对象exists():
判断查询集中是否有数据.
限制查询集:
查询集返回列表,可以使用下标的方法进行限制.等同于sql中的limit语句.
注意:下标不能是负数查询集的缓存:
- 概述:
每个查询集都包含一个缓存,来最小化的对数据库访问.
在新建的查询集中,缓存首次为空,第一次对查询集求值,会发生数据缓存,Django会见查询出来的数据做一个缓存(保存到内存中),并返回查询结构.以后的查询直接使用查询集的缓存.
- 概述:
字段查询:
概述:
实现了sql的where语句,作为方法filter(),exclude(),get()的参数语法:
属性名称__比较运算符=值.外键:
属性名_id转义:
like语句中使用%是为了匹配占位.如果要匹配数据中的%就要使用
where like \%
但是在查询集是使用1
2
3# 找出sname字段存在%的数据
# 不需要转义
filter(sname__contains='%')
比较运算符:
exact:
判断,大小写敏感.
filter(isDelete=False)contains:
是否包含,大小写敏感.1
studentList = Students.objects.filter(sname__contains='孙')
startswith,endswith:
和python普通的的startswith一样,以value开头/结尾1
studentList = Students.objects.filter(sname__startswith='孙')
上面四个函数在前面加一个i表示不区分大小写.
1
2
3
4iexact
icontains
istartswith
iendswithisnull,isnotnull:
是否为空1
filter(sname__isnull=False)
in:
是否包含1
2# 查找id在2,4,6,8的学生
studentList = Students.objects.fileter(id__in=[2,4,6,8])gt,gte,lt,lte:
大小于等于1
2# 查找年龄大于30的学生
studentList = Students.objects.filter(sage__gt=30)year,month,day,week_day,hour,minute,second:
日期时间相关:1
studentList = Students.objects.filter(lastTime__year=20)
跨关联关系:
处理join查询.
语法:模型类名__属性名__比较运算符1
2# 班级里面有名字叫何应良的学生 的班级有哪些?
gradeList = Gredes.objects.fileter(students__sname__contains='何应良')查询快捷:
使用pk代表数据表中的主键
聚合函数:
使用aggregate()函数返回聚合函数的值
Avg,Count,Max,Min,Sum1
2
3# 先引入
from django.db.models import Max
maxAge = Students.objects.aggregate(Max('sage'))F对象:
可以使用模型的A属性与B属性进行比较(就是一条数据里的两个值比较)
1
2
3from django.db.models import F
# 字段girlnum的值比boynum字段的值要大
Grades.objects.filter(girlnum__gt=F('boynum'))支持F对象的算术运算
1
2
3from django.db.models import F
# 字段girlnum的值比 boynum字段的值加上20 还要大
Grades.objects.filter(girlnum__gt=F('boynum')+20)Q对象:
概述:
过滤器的方法中的关键字参数,条件为AND模式.
就是说filter(键1=值1,键2=值2):
是且
的关系,就是说,要同时符合两种条件现在要进行OR查询,就要使用Q对象.
所以说:Q对象用于解决或的问题.Q()1
2
3
4from django.db.models import F
# id小于3或者年龄大于50的数据
Students.object.filter(Q(id__lte=3) | Q(age__gt = 50))上面就是使用两个Q对象,然后使用|连接,
如果只有一个Q对象,那就是用于匹配的,可以直接省去:1
2
3Students.object.filter(Q(id__lte=3))
# 等同于
Students.object.filter(id__lte=3)取反:在Q前面加一个波浪线
~
1
Students.object.filter(~Q(id__lte=3)