目录
3. 编写视图文件:mydemo/myapp/views.py
一、Django的Model模型介绍
- 模型是我们项目中的的数据信息源,它包含着储存数据的必要字段和行为。
- 通常,每个模型对应数据库中的一张表,每个属性对应一个字段
- 每个模型都是django.db.models.Model的一个Python 子类。(这个model里面封装了我们的增删改查操作)
- Django 提供一套自动生成的用于数据库访问的API;
- 模型与数据库的关系是ORM关系(对象-关系-映射)
- 为什么要用模型?
Model是MVC框架中重要的一部分, 负责在数据库中存取数据
它实现了数据模型与数据库的解耦,即不需要依赖于特定的数据库
通过简单的配置就可以轻松更换数据库
二、Model的开发流程
-
在models.py中定义模型类,要求继承自models.Model(注意:
addtime=models.DateTimeField(default=datetime.now)在后面执行迁移文件可能会报错:
AttributeError: module 'datetime' has no attribute 'now'
需要改成addtime=models.DateTimeField(default=datetime.datetime.now()))
from django.db import models from datetime import datetime # Create your models here. class Users(models.Model): #id = models.AutoField(primary_key=True) #主键可省略不写 name = models.CharField(max_length=32) age = models.IntegerField(default=20) phone = models.CharField(max_length=16) addtime=models.DateTimeField(default=datetime.now) #class Meta: # db_table = "myapp_users" # 指定表名
-
把应用加入settings.py文件的installed_app项
-
编辑myweb/settings.py文件,并将项目应用文件名添加到该INSTALLED_APPS设置。
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'myapp', #或全称:myapp.apps.MyappConfig ]
-
生成迁移文件
python3 manage.py makemigrations django.core.exceptions.ImproperlyConfigured: Error loading MySQLdb module: No mo dule named 'MySQLdb'. Did you install mysqlclient or MySQL-python? 安装上面"配置Mysql数据库"的第五步配置,或安装:pip install mysqlclient后就可以了 若执行python manage.py makemigrations命令(也可能人比较皮,把migrations文件夹给删了),会提示"No changes detected." 可能有用的解决方式如下: 先 python manage.py makemigrations --empty yourappname 生成一个空的initial.py 再 python manage.py makemigrations 生成原先的model对应的migration file
-
执行迁移
python3 manage.py migrate
-
使用模型类进行crud操作
from django.shortcuts import render
from django.http import HttpResponse
from myapp.models import Users
# Create your views here.
def index(requeest):
#添加操作
ob = Users() #实例化一个新对象(空对象)
ob.name = "张三"
ob.age = 20
ob.phone = '123456789'
ob.save() #新对象就是添加,已存在对象则是修改
#删除操作
mod = Users.objects #获取users的model对象
user = mod.get(id=1) #获取id值为1的数据信息
print(user.name)
user.delete()
#修改操作
ob = Users.objects.get(id=2)
ob.name = "小刘"
ob.age = 26
ob.save()
#数据查询
mod = Users.objects #获取Users模型的model操作对象
ulist = mod.all() #获取所有数据
ulist = mod.filter(name='小刘') #获取name值为小刘的信息
ulist = mod.filter(age=20) #获取所有age=20的信息
ulist = mod.order_by("age") #按age升序排序
ulist = mod.order_by("age")[:2] #按age升序排序,只获取前两条
for u in ulist:
print(u.id,u.name,u.age,u.phone,u.addtime)
return HttpResponse("首页")
增删改查操作要一条一条的执行, 可以进行注释。
三、定义Model模型
- 在模型中定义属性,会生成表中的字段
- Django根据属性的类型确定以下信息:
1.当前选择的数据库支持字段的类型
2.渲染管理表单时使用的默认html控件
3.在管理站点最低限度的验证
- Django会为表增加自动增长的主键列,每个模型只能有一个主键列。
- 属性命名限制
1.不能是Python的保留关键字
2.由于Django的查询方式,不允许使用连续的下划线
四、Model模型的实例
- 模型实例对象是通过objects属性获取,即Django为模型类提供的管理器。
objects:是Manager类型的对象,用于与数据库进行交互
- 实例的方法
__str__(self):重写object方法,此方法在将对象转换成字符串时会被调用
save( ):将模型对象保存到数据表中
delete( ):将模型对象从数据表中删除
五、Model模型的查询
模型查询
- 查询集表示从数据库中获取的对象集合
- 查询集可以含有零个、一个或多个过滤器
- 过滤器基于所给的参数限制查询的结果
- 从Sql的角度,查询集和select语句等价,过滤器像where和limit子句
- 接下来主要讨论如下知识点
- 查询集
- 字段查询:比较运算符,F对象,Q对象
1. 查询集
- 在管理器上调用过滤器方法会返回查询集
- 查询集经过过滤器筛选后返回新的查询集,因此可以写成链式过滤
- 惰性执行:创建查询集不会带来任何数据库的访问,直到调用数据时,才会访问数据库
- 何时对查询集求值:迭代,序列化,与if合用
-
返回查询集的方法,称为过滤器
- all() :查询所有数据
- filter() :过滤查询
- exclude()
- order_by() :排序
- values():一个对象构成一个字典,然后构成一个列表返回
-
写法:
filter(键1=值1,键2=值2) 等价于 filter(键1=值1).filter(键2=值2)
-
返回单个值的方法
- get():返回单个满足条件的对象
- 如果未找到会引发"模型类.DoesNotExist"异常
- 如果多条被返回,会引发"模型类.MultipleObjectsReturned"异常
- count():返回当前查询的总条数
- first():返回第一个对象
- last():返回最后一个对象
- exists():判断查询集中是否有数据,如果有则返回True
- get():返回单个满足条件的对象
限制查询集
-
查询集返回列表,可以使用下标的方式进行限制,等同于sql中的limit和offset子句
-
注意:不支持负数索引
-
使用下标后返回一个新的查询集,不会立即执行查询
-
如果获取一个对象,直接使用[0],等同于[0:1].get(),但是如果没有数据,[0]引发IndexError异常,[0:1].get()引发DoesNotExist异常
#这会返回前5个对象 LIMIT 5 Entry.objects.all()[:5] #这将返回第六个到第十个对象 OFFSET 5 LIMIT 5 Entry.objects.all()[5:10]
查询集的缓存
- 每个查询集都包含一个缓存来最小化对数据库的访问
-
在新建的查询集中,缓存为空,首次对查询集求值时,会发生数据库查询,django会将查询的结果存在查询集的缓存中,并返回请求的结果,接下来对查询集求值将重用缓存的结果
-
情况一:这构成了两个查询集,无法重用缓存,每次查询都会与数据库进行一次交互,增加了数据库的负载
print([e.title for e in Entry.objects.all()]) print([e.title for e in Entry.objects.all()])
-
情况二:两次循环使用同一个查询集,第二次使用缓存中的数据
querylist=Entry.objects.all() print([e.title for e in querylist]) print([e.title for e in querylist])
-
何时查询集不会被缓存:当只对查询集的部分进行求值时会检查缓存,但是如果这部分不在缓存中,那么接下来查询返回的记录将不会被缓存,这意味着使用索引来限制查询集将不会填充缓存,如果这部分数据已经被缓存,则直接使用缓存中的数据
2. 字段查询
- 实现where子名,作为方法filter()、exclude()、get()的参数
- 语法:属性名称__比较运算符=值
- 表示两个下划线,左侧是属性名称,右侧是比较类型
- 对于外键,使用“属性名_id”表示外键的原始值
- 转义:like语句中使用了%与,匹配数据中的%与,在过滤器中直接写,例如:filter(title__contains="%")=>where title like '%\%%',表示查找标题中包含%的
比较运算符
-
exact:表示判等,大小写敏感;如果没有写“ 比较运算符”,表示判等
filter(isDelete=False)
-
contains:是否包含,大小写敏感
exclude(btitle__contains='传')
-
startswith、endswith:以value开头或结尾,大小写敏感
exclude(btitle__endswith='传')
-
isnull、isnotnull:是否为null
filter(btitle__isnull=False)
-
在前面加个i表示不区分大小写,如iexact、icontains、istarswith、iendswith
-
in:是否包含在范围内
filter(pk__in=[1, 2, 3, 4, 5])
-
gt、gte、lt、lte:大于、大于等于、小于、小于等于
filter(id__gt=3)
-
year、month、day、week_day、hour、minute、second:对日期间类型的属性进行运算
filter(bpub_date__year=1980) filter(bpub_date__gt=date(1980, 12, 31))
跨关联关系的查询:处理join查询
-
语法:模型类名 <属性名> <比较>
-
注:可以没有__<比较>部分,表示等于,结果同inner join
-
可返向使用,即在关联的两个模型中都可以使用
filter(heroinfo_ _hcontent_ _contains='八')
聚合函数
-
使用aggregate()函数返回聚合函数的值
-
函数:Avg,Count,Max,Min,Sum
from django.db.models import Max maxDate = list.aggregate(Max('bpub_date'))
-
count的一般用法:
count = list.count()
六、用户信息管理实例
1. 创建数据库和表(若是执行表迁移,可跳过下面操作)
- 进入MySQL数据库创建数据库:mytest
-
进入数据库创建数据表:myapp_users
CREATE TABLE `myapp_users` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(32) NOT NULL, `age` tinyint(3) unsigned NOT NULL DEFAULT '20', `phone` varchar(16) DEFAULT NULL, `addtime` datetime(6) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
-
添加几条测试数据
2. 创建项目myweb和应用myapp
# 创建项目框架mydemo
$ django-admin startproject mydemo
$ cd mydemo
# 在项目中创建一个myapp应用
$ python manage.py startapp myapp
# 创建模板目录
$ mkdir templates
$ mkdir templates/myapp
$ cd ..
$ tree myweb
mydemo
├── mydemo
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── manage.py
├── myapp
│ ├── admin.py
│ ├── apps.py
│ ├── __init__.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
└── templates
└── myapp
3. 执行数据库连接配置,网站配置
- 编辑myweb/myweb/settings.py文件,配置数据库连接
...
#配置自己的服务器IP地址
ALLOWED_HOSTS = ['*']
...
#添加自己应用
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'myapp',
#或'myapp.apps.MyappConfig', #或者直接写 myapp
]
...
# 配置模板路径信息
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR,'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
...
# 数据库连接配置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'mytest',
'USER': 'root',
'PASSWORD': '',
'HOST': 'localhost',
'PORT': '3306',
}
}
4. 定义Model类
4.1 编辑mydemo/myapp/models.py
from django.db import models
class Users(models.Model):
#id = models.AutoField(primary_key=True) #主键可省略不写
name = models.CharField(max_length=32)
age = models.IntegerField(default=20)
phone = models.CharField(max_length=16)
addtime=models.DateTimeField(default=datetime.now)
def __str__(self):
return self.name+":"+self.phone
# 自定义对应的表名,默认表名:myapp_users
#class Meta:
# db_table="myapp_users"
如果出现报错:
AttributeError: module 'datetime' has no attribute 'now'
需要改成addtime=models.DateTimeField(default=datetime.datetime.now()))
4.2 测试Model类的使用
在项目根目录下执行命令: python manage.py shell
[root@localhost mydemo]# ls
mydemo manage.py myapp
[root@localhost mydemo]# python3 manage.py shell
Python 3.6.1 (default, Jul 18 2017, 01:35:19)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-18)] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from myapp.models import Users
>>> Users.objects.all()
<QuerySet [<Users: 张三:12345678901>, <Users: aa:13456789023>]>
>>> s = Users.objects.get(id=1)
>>> s.id
1
>>> s.name
'张三'
>>> s.age
20
>>> s.phone
'12345678901'
>>>
5. 实现Web端访问
5.1 编辑mydemo/mydemo/settings.py文件.做 ALLOWED_HOSTS 主机访问配置(若第三步已做可跳过此步骤)
#此处添加自己的IP地址
ALLOWED_HOSTS = ['*']
5.2 编写项目主路由urls配置,配置对myapp应用路由的访问连接配置
from django.contrib import admin
from django.urls import include,path
urlpatterns = [
#path('admin/', admin.site.urls),
path('', include('myapp.urls')),
]
5.3 配置当前应用myapp的路由配置
在myapp应用目录下创建一个路由文件urls.py文件,注意此文件编码为utf-8(建议复制一个)。
编辑应用中的路由配置文件:mydemo/myapp/urls.py, 内容如下:
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
]
5.4 编辑视图文件:mydemo/myapp/views.py,内容如下
#from django.shortcuts import render
from django.http import HttpResponse
from myapp.models import Users
def index(request):
try:
s = Users.objects.get(id=1)
return HttpResponse(s)
except:
return HttpResponse("没有找到对应的信息!")
5.5 测试
项目根目录下运行 pythons manage.py sunserver 0.0.0.0:8000
命令,开启服务:
[root@localhost mydemo]# python manage.py runserver 0.0.0.0:8000
Performing system checks...
System check identified no issues (0 silenced).
July 28, 2020 - 14:01:52
Django version 2.2.11, using settings 'myweb.settings'
Starting development server at http://0.0.0.0:8000/
Quit the server with CONTROL-C.
打开浏览器,在浏览其中输入网址测试:http://172.16.142.129:8000
显示结果:张三:12345678901
继续上面操作完成Web版的Users信息增 删 改 查
1. 准备模板文件,创建模板目录
- 在项目目录下创建templates模板目录
- 进入模板目录templates,在模板目录下创建应用名myapp的目录
- 进入myapp目录,在里面创建一个users目录
- 进入users目录,在里面创建文件:index.html,add.html,edit.html,menu.html,info.html
5 设置模板目录信息:编辑mydemo/mydemo/settings.py文件(若第三步已做可跳过此步骤)
...
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR,'templates'),],
'APP_DIRS': True,
...
2. 配置路由信息
打开文件:mydemo/myapp/urls.py路由文件,加入六条路由配置信息
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name="index"),
path('users', views.indexUsers, name="users"), #浏览用户信息
path('users/add', views.addUsers, name="addusers"), #加载添加用户信息表单
path('users/insert', views.insertUsers, name="insertusers"), #执行用户信息添加
path('users/<int:uid>/del', views.delUsers, name="delusers"), #执行用户信息删除
path('users/<int:uid>/edit', views.editUsers, name="editusers"), #加载用户信息编辑表单
path('users/update', views.updateUsers, name="updateusers"), #执行用户信息编辑
]
3. 编写视图文件:mydemo/myapp/views.py
# 注意:需导入from django.shortcuts import render
from django.shortcuts import render
from django.http import HttpResponse
from myapp.models import Users
def index(request):
try:
list = Users.objects.filter(id__in=[1,3,5])
s = ','.join([vo.name for vo in list])
#修改(将id值为5的age值改为30)
#ob = Users.objects.get(id=5)
#ob.age = 30
#ob.save()
#删除(删除id为3的信息)
#ob = Users.objects.get(id=3)
#ob.delete()
return HttpResponse(s)
except:
return HttpResponse("没有找到对应的信息!")
# 浏览用户信息
def indexUsers(request):
# 执行数据查询,并放置到模板中
list = Users.objects.all()
context = {"stulist":list}
return render(request,"myapp/users/index.html",context)
# 加载添加信息表单
def addUsers(request):
return render(request,"myapp/users/add.html")
# 执行信息添加操作
def insertUsers(request):
try:
ob = Users()
ob.name = request.POST['name']
ob.age = request.POST['age']
ob.phone = request.POST['phone']
ob.save()
context = {'info':'添加成功!'}
except:
context = {'info':'添加失败!'}
return render(request,"myapp/users/info.html",context)
# 执行信息删除操作
def delUsers(request,uid):
try:
ob = Users.objects.get(id=uid)
ob.delete()
context = {'info':'删除成功!'}
except:
context = {'info':'删除失败!'}
return render(request,"myapp/users/info.html",context)
# 加载信息编辑表单
def editUsers(request,uid):
try:
ob = Users.objects.get(id=uid)
context = {'user':ob}
return render(request,"myapp/users/edit.html",context)
except:
context = {'info':'没有找到要修改的信息!'}
return render(request,"myapp/users/info.html",context)
# 执行信息编辑操作
def updateUsers(request):
try:
ob = Users.objects.get(id= request.POST['id'])
ob.name = request.POST['name']
ob.age = request.POST['age']
ob.phone = request.POST['phone']
#ob.addtime = datetime.now
ob.save()
context = {'info':'修改成功!'}
except:
context = {'info':'修改失败!'}
return render(request,"myapp/users/info.html",context)
4. 编辑浏览信息视图文件:
文件位置:mydemo/templates/myapp/users/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>用户信息管理</title>
<script>
//自定义执行信息删除提示判断,参数uu是成功的删除url地址
function doDel(uu){
if(confirm("确定要删除吗?")){
//网页跳转
window.location=uu;
}
}
</script>
</head>
<body>
<center>
{% include 'myapp/users/menu.html' %}
<h3>浏览用户信息</h3>
<table width="800" border="1">
<tr>
<th>id号</th>
<th>姓名</th>
<th>年龄</th>
<th>电话</th>
<th>添加时间</th>
<th>操作</th>
</tr>
{% for stu in stulist %}
<tr>
<td>{
{ stu.id }}</td>
<td>{
{ stu.name }}</td>
<td>{
{ stu.age }}</td>
<td>{
{ stu.phone }}</td>
<td>{
{ stu.addtime|date:'Y-m-d H:i:s' }}</td>
<td>
<a href="{% url 'editusers' stu.id %}">编辑</a>
<a href="javascript:doDel('{% url 'delusers' stu.id %}');">删除</a>
</td>
</tr>
{% endfor %}
</table>
</center>
</body>
</html>
5. 编辑添加表单视图文件
文件位置:mydemo/templates/myapp/users/add.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>用户信息管理</title>
</head>
<body>
<center>
{% include "myapp/users/menu.html" %}
<h3>添加用户信息</h3>
<form action="{% url 'insertusers' %}" method="post">
{% csrf_token %}
<table width="280" border="0">
<tr>
<td>姓名:</td>
<td><input type="text" name="name"/></td>
</tr>
<tr>
<td>年龄:</td>
<td><input type="text" name="age"/></td>
</tr>
<tr>
<td>电话:</td>
<td><input type="text" name="phone"/></td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="添加"/>
<input type="reset" value="重置"/>
</td>
</tr>
</table>
</form>
</center>
</body>
</html>
6. 编辑信息表单视图文件
文件位置:mydemo/templates/myapp/users/edit.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>用户信息管理</title>
</head>
<body>
<center>
{% include "myapp/users/menu.html" %}
<h3>修改用户信息</h3>
<form action="{% url 'updateusers' %}" method="post">
<input type="hidden" name="id" value="{
{ user.id}}"/>
{% csrf_token %}
<table width="280" border="0">
<tr>
<td>姓名:</td>
<td><input type="text" name="name" value="{
{ user.name }}"/></td>
</tr>
<tr>
<td>年龄:</td>
<td><input type="text" name="age" value="{
{ user.age }}"/></td>
</tr>
<tr>
<td>电话:</td>
<td><input type="text" name="phone" value="{
{ user.phone }}"/></td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="编辑"/>
<input type="reset" value="重置"/>
</td>
</tr>
</table>
</form>
</center>
</body>
</html>
7. 编辑公共导航栏页视图文件
文件位置:mydemo/templates/myapp/users/menu.html
<h2>用户信息管理</h2>
<a href="{% url 'users' %}">浏览用户</a> |
<a href="{% url 'addusers' %}">添加用户</a>
<hr/>
文件位置:mydemo/templates/myapp/users/info.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>用户信息管理</title>
</head>
<body>
<center>
{% include "myapp/users/menu.html" %}
<h3>{
{ info }}</h3>
</center>
</body>
</html>