内容学习自 BV1Jf4y1B7SV 以及大部分博客等等...
1.路由 urls
介绍几种写url的方式
首先定义总的路由
总路由 urls.py:
在settings.py文件中会有这一段:
ROOT_URLCONF = 'demo.urls'
ROOT_URLCONF指明项目的路由入口文件,因此要配置总路由demo/urls.py:
from django.urls import include
urlpatterns = [
# 系统默认自带的路径用于管理数据库,现在我们不用
# path('admin/', admin.site.urls),
# 使用include()引入应用中的路由(子路由)
path("myapp/",include('myapp.urls')) # 在总路由中导入子路由文件
]
1.1基本分配方式
# myapp/urls.py
from django.urls import path,re_path
# 导入myapp的视图文件
from . import views
urlpatterns = [
# 通过查找myapp中的views中的视图函数,分配给不同的路径
path('index' , views.index , name = "index"),
path('add' , views.add , name = "add"),
...
]
在视图中使用:
# myapp/virews.py
from django.http import HttpResponse
def index():
return Httpresponse("index...")
def add(request):
return HttpResponse("add...")
1.2路径转换器
# myapp/urls.py
from django.urls import path,re_path
# 导入myapp的视图文件
from . import views
urlpatterns = [
# 将sid定义为int类型,name定义为str类型,并且传入给 views.find
# 这样子的的话可以访问 /find/ 或者 /find/123 或者 /find/123/zhangsan
path('find/',views.find),
path('find/<int:sid>',views.find),
path('find/<int:sid>/<str:name>' , views.find , name = "find3"),
...
]
在视图中使用(可以拿到对应的参数):
# myapp/views.py
from django.http import HttpResponse
def find(request,sid = 1,name = ''):
return HttpResponse("find...%d:%s"%(sid,name))
-
默认情况下,以下路径转换器可用:
str-匹配任何非空字符串,但路径分隔符除外'/'。如果表达式中不包含转换器,则为默认设置。int-匹配零或任何正整数。返回一个int。slug-匹配由ASCII字母或数字以及连字符和下划线字符组成的任何条形字符串。例如, building-your-1st-django-site。uuid-匹配格式化的UUID。为防止多个URL映射到同一页面,必须包含破折号并且字母必须小写。例如,075194d3-6885-417e-a8a8-6c931e272f00。返回一个 UUID实例。path-匹配任何非空字符串,包括路径分隔符 '/'。这样,您就可以匹配完整的URL路径,而不是像一样匹配URL路径的一部分str。
1.3正则表达式
# myapp/urls.py
from django.urls import path,re_path
# 导入myapp的视图文件
from . import views
urlpatterns = [
# 正则方式一,可以获取指定参数的名称: /(?P<指定参数名字>...)/
#假如指定了参数名称,那么在视图中获取的参数必须与这里的名称一致
re_path(r"^fun/(?P<year>[0-9]{4})/(?P<mouth>[0-9]{2})/$",views.fun),
# 正则方式二(不推荐),隐藏参数的名称: /(...)/
# re_path(r"^fun/([0-9]{4})/([0-9]{2})/$",views.fun),
...
]
在视图中使用(可以拿到对应的参数):
def fun(request,year,mouth):
# 通过正则匹配出来的是字符串类型
# print(type(year))
# print(type(mouth))
return HttpResponse("路由参数:年:" + str(year) + " 月:" + str(mouth))
2.模型 model
展示如何在视图中操作表
首先在应用中使用一个数据表:
| id | name | age | phone | addtime |
|---|---|---|---|---|
| 1 | 张三 | 13 | 13456789 | Dec. 21, 2021, 11:57 p.m |
| 2 | 李四 | 15 | 13458789 | Dec. 21, 2021, 11:58 p.m |
| ...... |
模型myapp/model.py:
#myapp/model.py
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" # 指定表名
2.1添加操作
首先是引入当前app目录下的model.py中的某个模型类,如下使用User类
# myapp/views.py
from django.shortcuts import render
from django.http import HttpResponse
from myapp.models import Users
def index(request):
"""方式一:"""
# 获取到model中的User表
ob = Users() # 实例化一个新对象(空对象)
# 添加操作 当访问到当前这个页面时执行添加操作
ob.name = "张三"
ob.age = 20
ob.phone = 1234567
# 保存操作
ob.save() # 新对象就是添加,已存在对象则是修改
"""
方式二:
ob = User(
name = "张三",
age = 20,
phone = 1234567
)
ob.save()
"""
return Httpresponse('添加完成')
添加操作的另一种方法:
# 省去了 save() 操作,更加推荐
def index(request):
User.object.create(
name = "张三",
age = 20,
phone = 1234567
)
return Httpresponse('添加完成')
关于添加操作中的外键问题:
2.2删除操作
# myapp/views.py
from django.shortcuts import render
from django.http import HttpResponse
from myapp.models import Users
def index(request):
# 删除操作 (确保获取到的数据信息存在,否则报错)
mod = Users.objects # 获取Users的model对象
user = mod.get(id = 3) # 获取id为2的数据信息
user.delete() # 执行删除操作
return Httpresponse('删除完成')
2.3修改操作
# myapp/views.py
from django.shortcuts import render
from django.http import HttpResponse
from myapp.models import Users
def index(request):
ob = Users.objects.get(id = 1)
ob.name = '觉罗'
ob.age = 26
ob.save()
return Httpresponse('修改完成')
2.4 查询操作
查询操作有关的东西很多,这里直接使用来自别的老师的资料 在进行查询操作时,有两个模型类:
BookInfo
#定义图书模型类BookInfo
class BookInfo(models.Model):
btitle = models.CharField(max_length=20, verbose_name='名称')
bpub_date = models.DateField(verbose_name='发布日期')
bread = models.IntegerField(default=0, verbose_name='阅读量')
bcomment = models.IntegerField(default=0, verbose_name='评论量')
is_delete = models.BooleanField(default=False, verbose_name='逻辑删除')
class Meta:
db_table = 'tb_books' # 指明数据库表名
verbose_name = '图书' # 在admin站点中显示的名称
verbose_name_plural = verbose_name # 显示的复数名称
def __str__(self):
"""定义每个数据对象的显示信息"""
return self.btitle
Heroinfo
class HeroInfo(models.Model):
GENDER_CHOICES = (
(0, 'female'),
(1, 'male')
)
hname = models.CharField(max_length=20, verbose_name='名称')
hgender = models.SmallIntegerField(choices=GENDER_CHOICES, default=0, verbose_name='性别')
hcomment = models.CharField(max_length=200, null=True, verbose_name='描述信息')
hbook = models.ForeignKey(BookInfo, on_delete=models.CASCADE, verbose_name='图书') # 外键
is_delete = models.BooleanField(default=False, verbose_name='逻辑删除')
class Meta:
db_table = 'tb_heros'
verbose_name = '英雄'
verbose_name_plural = verbose_name
def __str__(self):
return self.hname
形成的表分别为:
Bookinfo
HeroInfo
其中HeroInfo中的外键是hbook,外键对应BookInfo中的主键
2.4.1 基本查询
get 查询单一结果,如果不存在会抛出模型类.DoesNotExist异常。
all 查询多个结果。
count 查询结果数量。
2.4.2 过滤查询-常用
实现SQL中的where功能,包括
- filter 过滤出多个结果
- exclude 排除掉符合条件剩下的结果
- get 过滤单一结果
对于过滤条件的使用,上述三个方法相同,故仅以filter进行讲解。
过滤条件的表达语法如下:
属性名称__比较运算符=值
# 属性名称和比较运算符间使用两个下划线,所以属性名不能包括多个下划线
1)相等
exact:表示判等。
例:查询编号为1的图书。
BookInfo.objects.filter(id__exact=1)
可简写为:
BookInfo.objects.filter(id=1)
2)模糊查询
contains:是否包含。
说明:如果要包含%无需转义,直接写即可。
例:查询书名包含'传'的图书。
BookInfo.objects.filter(btitle__contains='传')
startswith、endswith:以指定值开头或结尾。
例:查询书名以'部'结尾的图书
BookInfo.objects.filter(btitle__endswith='部')
以上运算符都区分大小写,在这些运算符前加上i表示不区分大小写,如iexact、icontains、istartswith、iendswith.
3) 空查询
isnull:是否为null。
例:查询书名不为空的图书。
BookInfo.objects.filter(btitle__isnull=False)
4) 多项查询
in:是否包含在指定项内。
例:查询编号为1或3或5的图书
BookInfo.objects.filter(id__in=[1, 3, 5])
5)比较查询
- gt 大于 (greater then)
- gte 大于等于 (greater then equal)
- lt 小于 (less then)
- lte 小于等于 (less then equal)
例:查询编号大于3的图书
BookInfo.objects.filter(id__gt=3)
不等于的运算符,使用exclude()过滤器。
例:查询编号不等于3的图书
BookInfo.objects.exclude(id=3)
6)日期查询
year、month、day、week_day、hour、minute、second:对日期时间类型的属性进行运算。
例:查询1980年发表的图书。
BookInfo.objects.filter(bpub_date__year=1980)
例:查询1980年1月1日后发表的图书。
BookInfo.objects.filter(bpub_date__gt=date(1990, 1, 1))
2.4.3 过滤查询-F对象
之前的查询都是对象的属性与常量值比较,两个属性怎么比较呢? 答:使用F对象,被定义在django.db.models中。
语法如下:
F(属性名)
例:查询阅读量大于等于评论量的图书。
from django.db.models import F
BookInfo.objects.filter(bread__gte=F('bcomment'))
可以在F对象上使用算数运算。
例:查询阅读量大于2倍评论量的图书。
BookInfo.objects.filter(bread__gt=F('bcomment') * 2)
2.4.4 过滤查询-Q对象
多个过滤器逐个调用表示逻辑与关系,同sql语句中where部分的and关键字。
例:查询阅读量大于20,并且编号小于3的图书。
BookInfo.objects.filter(bread__gt=20,id__lt=3)
或
BookInfo.objects.filter(bread__gt=20).filter(id__lt=3)
如果需要实现逻辑或or的查询,需要使用Q()对象结合|运算符,Q对象被义在django.db.models中。
语法如下:
Q(属性名__运算符=值)
例:查询阅读量大于20的图书,改写为Q对象如下。
from django.db.models import Q
BookInfo.objects.filter(Q(bread__gt=20))
Q对象可以使用&、|连接,&表示逻辑与,|表示逻辑或。
例:查询阅读量大于20,或编号小于3的图书,只能使用Q对象实现
BookInfo.objects.filter(Q(bread__gt=20) | Q(pk__lt=3))
Q对象前可以使用~操作符,表示非not。
例:查询编号不等于3的图书。
BookInfo.objects.filter(~Q(pk=3))
2.4.5 过滤查询-聚合函数
使用aggregate()过滤器调用聚合函数。聚合函数包括:Avg 平均,Count 数量,Max 最大,Min 最小,Sum 求和,被定义在django.db.models中。
例:查询图书的总阅读量。
from django.db.models import Sum
BookInfo.objects.aggregate(Sum('bread'))
注意aggregate的返回值是一个字典类型,格式如下:
{'属性名__聚合类小写':值}
如:{'bread__sum':3}
使用count时一般不使用aggregate()过滤器。
例:查询图书总数。
BookInfo.objects.count()
注意count函数的返回值是一个数字。
2.4.6 排序
使用order_by对结果进行排序
BookInfo.objects.all().order_by('bread') # 升序
BookInfo.objects.all().order_by('-bread') # 降序
2.4.7 关联查询
由一到多的访问语法:
一对应的模型类对象.多对应的模型类名小写_set
例:
b = BookInfo.objects.get(id=1)
b.heroinfo_set.all()
由多到一的访问语法:
多对应的模型类对象.多对应的模型类中的关系类属性名
例:
h = HeroInfo.objects.get(id=1)
h.hbook
访问一对应的模型类关联对象的id语法:
多对应的模型类对象.关联类属性_id
例:
h = HeroInfo.objects.get(id=1)
h.hbook_id
2.4.8 关联过滤查询
由多模型类条件查询一模型类数据:
语法如下:
关联模型类名小写__属性名__条件运算符=值
注意:如果没有"__运算符"部分,表示等于。
例:
查询图书,要求图书英雄为"孙悟空"
BookInfo.objects.filter(heroinfo__hname='孙悟空')
查询图书,要求图书中英雄的描述包含"八"
BookInfo.objects.filter(heroinfo__hcomment__contains='八')
由一模型类条件查询多模型类数据:
语法如下:
一模型类关联属性名__一模型类属性名__条件运算符=值
注意:如果没有"__运算符"部分,表示等于。
例:
查询书名为“天龙八部”的所有英雄。
HeroInfo.objects.filter(hbook__btitle='天龙八部')
查询图书阅读量大于30的所有英雄
HeroInfo.objects.filter(hbook__bread__gt=30)
2.5 模型类的补充
字段类型
| 类型 | 说明 |
|---|---|
| AutoField | 自动增长的IntegerField,通常不用指定,不指定时Django会自动创建属性名为id的自动增长属性 |
| BooleanField | 布尔字段,值为True或False |
| NullBooleanField | 支持Null、True、False三种值 |
| CharField | 字符串,参数max_length表示最大字符个数 |
| TextField | 大文本字段,一般超过4000个字符时使用 |
| IntegerField | 整数 |
| DecimalField | 十进制浮点数, 参数max_digits表示总位数, 参数decimal_places表示小数位数 |
| FloatField | 浮点数 |
| DateField | 日期, 参数auto_now表示每次保存对象时,自动设置该字段为当前时间,用于"最后一次修改"的时间戳,它总是使用当前日期,默认为False; 参数auto_now_add表示当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为False; 参数auto_now_add和auto_now是相互排斥的,组合将会发生错误 |
| TimeField | 时间,参数同DateField |
| DateTimeField | 日期时间,参数同DateField |
| FileField | 上传文件字段 |
| ImageField | 继承于FileField,对上传的内容进行校验,确保是有效的图片 |
选项
| null | 如果为True,表示允许为空,默认值是False |
|---|---|
| blank | 如果为True,则该字段允许为空白,默认值是False |
| db_column | 字段的名称,如果未指定,则使用属性的名称 |
| db_index | 若值为True, 则在表中会为此字段创建索引,默认值是False |
| default | 默认 |
| primary_key | 若为True,则该字段会成为模型的主键字段,默认值是False,一般作为AutoField的选项使用 |
| unique | 如果为True, 这个字段在表中必须有唯一值,默认值是False |
关于外键
在设置外键时,需要通过on_delete选项指明主表删除数据时,对于外键引用表数据如何处理,在django.db.models中包含了可选常量:
- CASCADE 级联,删除主表数据时连通一起删除外键表中数据
- PROTECT 保护,通过抛出ProtectedError异常,来阻止删除主表中被外键应用的数据
- SET_NULL 设置为NULL,仅在该字段null=True允许为null时可用
- SET_DEFAULT 设置为默认值,仅在该字段设置了默认值时可用
- SET() 设置为特定值或者调用特定方法
3.视图 views
3.1Httpresponse对象
3.1.1 不用模板,直接返回数据
# views.py
def index(request):
# 直接返回
return HttpResponse('<h3>直接返回数据</h3>')
# 设置响应体的类型以及状态码,不设置的时候默认文本类型为text/html,状态码为200
return HttpResponse('<h2>weather2</h2>',content_type='text/html',status=203)
3.1.2 调用模板返回数据
# views.py
def index1(request):
return render(request,'myapp/index1.html')
3.1.3 重定向
一种方法是使用reverse()反向解析出地址
# views.py
from django.shortcuts import render,redirect
from django.urls import reverse
def index2(request):
# 3.1.使用redirect重定向,reverse重定向到name为index1的地址,
return redirect(reverse('index1'))
# 3.2.使用js代码进行重定向
# return HttpResponse('<script>alert("即将重定向!");location.href("http://www.baidu.com")</script>')
另外也可以给视图起名字,直接通过name重定向,比较推荐
# urls.py
re_path(r"^weather1/(?P<city>[a-zA-Z]+)/(?P<year>[0-9]{4})$",views.weather1,name = "weather1"),
re_path(r"^re_direct/$",views.re_direct,name="re_direct")
# views.py
def re_direct(request):
# 直接找到name为weather1的路径,还可以指定参数
return redirect('weather1',city='beijin',year=2014)
# 如果在路由前面加/则表示从跟路由开始进行重定向,不加/则从当前路由开始重定向
# localhost:8080/weather1/beijin/2015
# return redirect('/weather1/beijin/2015')
3.1.4 返回json数据
Jsonresponse 中应该传递一个字典对象,如果是列表类型的应该加safe=Flase
不加safa=Flase,传递的只能是字典:
#views.py
from django.http import HttpResponse,JsonResponse
def res_json(request):
context = {
'name':'zhangsan',
'age':18,
'hobby':[
{'work':'good'},
{'play':'normal'}
]
}
return JsonResponse(context)
加上safa=Flase,传递的可以是字典或者是列表:
#views.py
from django.http import HttpResponse,JsonResponse
def res_json(request):
context = [1,2,3,4,5]
return JsonResponse(context)
3.1.5 返回错误,f12->network->status:404
from django.http import Http404
def index4(request):
# 5.1返回一个404的错误页面
# raise Http404('发生未知错误')
# 5.2返回一个404,没有去加载404的模板页面
# return HttpResponseNotFound('<h1>发生未知错误<h/2>')
# 直接返回一个状态码
return HttpResponse(status=403)
3.1.6 在视图中使用类
# views.py
class MyView(View):
# 指的是get请求
def get(self, request, *args, **kwargs):
return HttpResponse('Hello, World!')
# urls.py
from myapp.views import MyView
urlpatterns = [
# 其中as_view()是接受请求并返回响应的可调用视图:
# ['get', 'post', 'put', 'patch', 'delete, 'options'.]
path('index5/',MyView.as_view(),name = 'index5'),
]
3.1.7 使用cookie
可以通过HttpResponse对象中的set_cookie方法来设置cookie,是键值对的形式
可以通过delete_cookie对cookie进行删除
# views.py
def get_cookie(request):
response = HttpResponse('设置了cookie!')
# 第一次访问没有名称为name的cookie值,第二次访问后就获得了name值为zhangsan的cookie值
print(request.COOKIES.get('name',None))
#设置cookie值,此外可以设置有效期1小时
response.set_cookie('name','zhangsan',max_age=3600)
# 删除cookie
# response.delete_cookie('name')
return response
访问的时候可以通过request.COOKIES进行获取
def demo_view(request):
cookie1 = request.COOKIES.get('name')
print(cookie1)
return HttpResponse('OK')
3.2Httprequest对象
准备工作:
路由匹配:
# urls.py
path('index7',views.index7,name = 'index7'),
在模板中传递参数id=100&name=zhangsan&age=21,使最终视图能够获取到这些参数:
<!--index7.html-->
<a href="{% url 'index7' %}?id=100&name=zhangsan&age=21">
<h3>5.测试request请求对象</h3>
</a><br>
视图:
# views.py
from django.http import HttpResponse
def index7(request):
3.2.1 request中的get请求(重要)
request.GET只是一个属性,最终会返回一个QuesyDict对象
request.GET.get('参数名','默认值')是字典自带的方法
也可以使用
request.GET.getlist('参数名')取一键多值,假如模板中传输的参数是a=200&a=500,那么request.GET.getlist('a')获得最终结果为['200','500']
# GET:一个类似于字典的对象,包含get请求方式的所有参数
# 写法一:请求不到参数的时候会报错
# print("get请求的参数:" + str(request.GET))
# print("get请求的参数中的id参数的值:" + request.GET['id'])
# print("get请求的参数中的name参数的值:" + request.GET['name'])
# print("get请求的参数中的age参数的值:" + request.GET['age'])
# 写法二:
# 其中'name'指参数name,另一个参数为默认值,请求不到的时候设置为该默认值
print("get请求的参数中的id参数的值:" + request.GET.get('id', '0'))
print("get请求的参数中的name参数的值:" + request.GET.get('name', 'lisi'))
print("get请求的参数中的age参数的值:" + request.GET.get('age', '10'))
3.2.2 request中的post请求(重要)
用来获取请求体中的表单数据,request.POST只是一个属性,获取到的是Querydict对象
假如我现在使用Postwoman发送一个post请求到此,参数name=lisi,name=zhangsan,age=15
# request.POST:一个类似于字典的对象,包含post请求方式的所有参数
print(request.POST.getlist('name')) #['lisi','zhangsan']
print(request.POST.get('age')) # 15
注意: request.POST只能取到Content-Type(请求头)为application/x-www-form-urlencoded(form表单默认格式)的数据,如果请求头为application/json(json格式),multipart/form-data(文件)等格式无法取到,只有在request.body里面能取到原生的数据。当发送过来的是JSON数据是,request.POST取到的数据是空的,这时只有用request.body取,再反序列化才能使用。
3.2.3 request.body请求(重要)
request.body返回bytes类型的数据,它能够获取到前端传过来的json格式的数据,现在使用Postwoman发送json数据
# request.body 为bytes数据
bytes = request.body
# 经过decode变成字符串
str = bytes.decode()
# 将字符串转化为字典
dirt = json.loads(str)
print(dirt)
最后打印字典dirt
{'id': '8989-dddvdg', 'name': '文章标题-JSON格式参数演示', 'brief': '快速入门json参数', 'category': '分类'}
3.2.4 request.user(重要)
如果当前没有登录,那么 request.user 获取到的是一个匿名用户AnonymousUser
如果登录了那么就会获取到当前的登录对象
print(request.user) #
3.2.5 其他Httprequest对象属性
request.path
# path:一个字符串,表示请求的页面的完整路径,不包含域名
print("请求路径:" + request.path)
request.method
# method:一个字符串,表示请求使用的HTTP方法,常用值包括:'GET'、'POST'
print("请求方法:" + request.method)
request.encoding
# encoding:如果为None则表示使用浏览器的默认设置,一般为utf - 8
# 这个属性是可写的,可以通过修改它来修改访问表单数据使用的编码,接下来对属性的任何访问将使用新的encoding值
print("使用编码:" + str(request.encoding))
request.FILES
# FILES:一个类似于字典的对象,包含所有的上传文件
print("请求FILES:" + str(request.FILES))
获取cookie
# COOKIES:一个标准的Python字典,包含所有的cookie,键和值都为字符串
print("请求COOKIES:" + str(request.COOKIES))
request.session
# session:一个既可读又可写的类似于字典的对象,表示当前的会话,只有当Django,启用会话的支持时才可用,详细内容见“状态保持”
print("请求session:" + str(request.session))
return HttpResponse("请在终端中查看")
3.3 类视图
类视图需要继承 View,相应的假如浏览器发送的是get请求,那么将会自动执行里面的get函数,如果是其他的请求则会执行其他的函数,如put请求则会执行put函数,delete请求则会执行delete函数
# views.py
from django import views
from django.http import HttpResponse
class createbooks(views.View):
def get(self,request):
return HttpResponse('响应get请求')
def put(self,request):
return HttpResponse('响应put请求')
假如在路径配置中有传入参数,如下传入id:
from django.urls import re_path
from . import views
"""
要注意的是与函数视图不同,类视图作为参数传进去path或re_path的格式为
views.类.as_view()
"""
re_path(r"^books/(?P<id>\d+)/$",views.BookDetailView.as_view(),name = "BookDetailView")
那么接收的时候在类视图中的函数获取
# views.py
from django import views
from django.http import HttpResponse
"""
下面的id就是接收的参数
"""
class createbooks(views.View):
def get(self,request,id):
print(str(id))
return HttpResponse('响应get请求')
def put(self,request,id):
print(str(id))
return HttpResponse('响应put请求')
4.模板 templates
首先定义总的视图:
def demo1(request):
context = {}
context['name'] = 'ZhangSan'
context['a'] = [10, 20, 30]
context['stu'] = {'name':'lisi','age':20}
data = [
{'name': '张翠山', 'sex': 1, 'age': 40, 'state': 0},
{'name': '殷素素', 'sex': 0, 'age': 38, 'state': 2},
{'name': '张无忌', 'sex': 1, 'age': 20, 'state': 1},
{'name': '赵敏', 'sex': 0, 'age': 18, 'state': 2}
]
context['dlist'] = data
context['time'] = datetime.now
context['m1'] = 100
context['m2'] = 20
return render(request,'myapp/demo1.html',context)
4.1基本语法
<!-- myapp/demo1.html-->
<p>{{ name }}</p>
<p>{{ a.0 }}   {{ a.1 }}   {{ a.2 }}</p>
<p>{{ stu.name }} {{ stu.age }}</p>
<table>
<tr>
<td>姓名</td>
<td>性别</td>
<td>年龄</td>
<td>状态</td>
</tr>
{% for list in dlist %}
<tr>
<td>{{ list.name }}</td>
<td>
{% if list.sex == 1 %}
男
{% else %}
女
{% endif %}
</td>
<td>{{ list.age }}</td>
<td>{% if list.state == 0 %}
管理员
{% elif list.state == 1 %}
VIP用户
{% else %}
<span style="color: red">禁用账户</span>
{% endif %}
</td>
</tr>
{% endfor %}
</table>
4.2使用过滤器
<!-- myapp/demo1.html-->
<p>大写:{{ name|upper }}</p> <!-- 转为小写 -->
<p>小写:{{ name|lower }}</p> <!-- 关闭HTML自动转义 -->
<p>时间:{{ time|date:'Y-m-d H:i:s w' }}</p>
<p>拼接:{{ a|join:':' }}</p> <!-- 列表以冒号进行拼接 -->
4.3使用运算
<!-- myapp/demo1.html-->
<p>两个数:{{ m1 }},{{ m2 }}</p>
<p>m1+m2:{{ m1|add:m2 }}</p>
<p>m1-20:{{ m1|add:-20 }}</p>
<p>m1*m2:{% widthratio m1 1 m2 %}</p>
<p>m1/m2:{% widthratio m1 m2 1 %}</p>
4.4自定义
首先在当前应用目录下创建一个templatetags模板标签目录,建议内放一个__init__.py的空文件
然后在templatetags目录下创建一个模板标签文件pagetag.py,具体代码如下:
# pagetag.py
from django import template
register = template.Library()
# 自定义过滤器(实现大写转换)
@register.filter
def myupper(val):
# print ('val from template:',val)
return val.upper()
# 自定义标签(实现减法计算)
# from django.utils.html import format_html
@register.simple_tag
def jian(a, b):
res = int(a) - int(b)
return res
使用:
<!-- myapp/demo1.html-->
<p>自定义过滤器:{{ name|myupper }}</p>
<p>自定义标签:{% jian m1 m2 %}</p>
4.5 反向解析
假如子路由有配置:
from django.urls import path
from . import views
urlpatterns =
path('database_show/<int:Pindex>',views.database_show,name="database_show")
]
方式一:
{% url 'database_show' 1 2 3 %}
那么在浏览器打开的路径是localhost:8080/database_show/1/2/3
方式二:
{% url 'database_show' 1 2 3 %}?name=lala&age=8
那么在浏览器打开的路径是localhost:8080/database_show/1/2/3?name=lala&age=8
5.设置 settings
模板位置与静态资源位置
首先先要有BASE_DIR
# os.path.abspath(__file__) 指的是返回当前sttings.py的绝对路径
# os.path.dirname(os.path.abspath(__file__)) 返回的是settings.py所在的目录的绝对路径
# os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 返回的最终是文件的根目录的绝对路径
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
在TEMPLATES中的DIR项中配置:
# 指的就是在项目的根目录下下的templates目录
'DIRS': [os.path.join(BASE_DIR, 'templates')]
静态资源配置:
STATIC_URL = '/static/'
STATICFLIES_DIRS = (os.path.join(BASE_DIR,"static"))
密钥
每一个Django项目中的密钥都不一样,将来如果要进行加密的话可以使用此密钥
SECRET_KEY = 'l!&g(!-m1ruv*m9&+9qgn=k$n-kn1bs&hw5sy7(fbd!dtof=r8'
debug功能
在开发中一般会设置为true,将来项目上线时需要改为false
DEBUG = True
访问
允许哪个域名访问Django项目,一般在开发中会设置*
ALLOWED_HOSTS = ['*']
应用
在开发中假如创建了一个myapp的应用,应该将其写上去上去
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'myapp'
]
数据库配置
一般我会选择MySQL
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'mytest', #选择数据库的名,请确认你的mysql中有这个库
'USER': 'root',# 数据库的用户名
'PASSWORD': '', # 数据库的密码,有密码的话要填上去
'HOST': 'localhost',
'PORT': '3306',
}
}
6.其他的问题
6.1基本命令行
新建Django命令:django-admin startproject project_name
新建app:python manage.py startapp app_name
使用开发服务器运行项目:python manage.py runserver
指定端口运行项目:python manage.py runserver 8080
生成文件迁移:python manage.py makemigrations
执行文件迁移:python manage.py migrate
6.2命名空间的问题
假如定义了两个应用app1和app2,他们的路由规则如下:
# 总路由 urls.py
urlpattern = [
path('',include('app1.urls'))
path('',include('app2.urls'))
]
# app1/urls.py
urlpattern = [
path('index1',views.index1,name='index1')
]
# app2/urls.py
urlpattern = [
path('index1',views.index1,name='index1')
]
当其中一个应用使用反向路由解析的时候,reverse('index1'),系统会选择文件在上面的应用的路由,这样的话不得不使用命名空间来加以约束,在总路由中配置namespace:
# 总路由 urls.py
urlpattern = [
path('',include('app1.urls',namespace='app1'))
path('',include('app2.urls',namespace='app2'))
]
接着在app1以及app2中添加app_name:
# app1/urls.py
app_name = 'app1'
# app2/urls.py
app_name = 'app2'
在使用反向解析的时候就能够指定想要的路径了,语法'命名空间:路由别名'
#访问的是名字为app1应用里面的index1
reverse('app1:index1')
#访问的是名字为app2应用里面的index1
reverse('app2:index1')
6.3 在Windows下使用Redis
首先再settings.py中添加:
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
# redis服务的端口,最后的斜杠后的数字指定的是redis中的1号数据库
"LOCATION": "redis://127.0.0.1:6379/1",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
}
}
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "default"
选择一个视图,进行配置session
def set_session(request):
# session依赖cookie
# 当代码执行到这里时,session设置到redis数据库,同时生成了session_id并通过后期的响应设置到浏览器的cookie中
request.session['name'] = 'zhangsan'
# 第一次设置读取到名字为name的session,以后也能读取到name
name = request.session.get('name')
print(name)
return HttpResponse('<h2>设置session</h2>')
最后访问该视图的页面,并在redis中查看:
6.4数据类型转化问题
1.将QuerySet转化为字典dict
QuerySet是对从数据库中查询出来的数据进行的封装,假如没有使用DRF【使用DRF框架则另说】,那么需要手动进行数据类型的转化
from django import views
from .models import BookInfo
class BookListView(views.View):
def get(self,request):
"""
在本例中,BookInfo为一个model类,
有btitle,bpub_date,bread,bcomment和is_delete这几个字段
"""
# books 即获取到的多个查询集
books = BookInfo.objects.all()
# 初始化列表
book_list = list()
# 通过for循环遍历多个查询集
for book in books:
# 获取查询集的每一项并放入字典one中,列表book_list获取到每个字典
one = dict()
one['btitle'] = book.btitle
one['bpub_date'] = book.bpub_date
one['bread'] = book.bread
one['bcomment'] = book.bcomment
one['is_delete'] = book.is_delete
book_list.append(one)
""" 处理完后的book_list为列表,每项都是一个字典 """
# 处理字典格式一
# result = dict()
# result['allbook'] = book_list
# 处理字典格式二
result = {
'allbooks': book_list
}
return JsonResponse(result)
最后在浏览器响应:
...
2.将表单传输过来的数据保存到数据库中
如果前端传输过来的是表单数据,用request.POST进行获取
如果前端传输过来的是json数据,用request.body进行获取
最后保存
"""
只展示request.body用法,request.POST详见: 3.视图 views
"""
def put(self,request,id):
try:
book = BookInfo.objects.get(id = id)
except BookInfo.DoesNotExist:
return HttpResponse({'mesage':'修改的数据不存在'},status=404)
# request.body 为bytes数据
bytes = request.body
# 进行解码
string = bytes.decode()
# 转化为字典格式
dict = json.loads(string)
# 赋值与保存
book.btitle = dict['btitle']
book.bpub_date = dict['bpub_date']
book.save()
return HttpResponse('修改成功')