Django 个人笔记

230 阅读19分钟

内容学习自 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

展示如何在视图中操作表

首先在应用中使用一个数据表:

idnameagephoneaddtime
1张三1313456789Dec. 21, 2021, 11:57 p.m
2李四1513458789Dec. 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 image.png

HeroInfo image.png

其中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)

image.png
加上safa=Flase,传递的可以是字典或者是列表:

#views.py

from django.http import HttpResponse,JsonResponse
def res_json(request):
    context = [1,2,3,4,5]
    return JsonResponse(context)

image.png

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数据

image.png

# 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 }} &nbsp {{ a.1 }} &nbsp {{ 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>

image.png

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>  <!-- 列表以冒号进行拼接 -->

image.png

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命名空间的问题

假如定义了两个应用app1app2,他们的路由规则如下:

# 总路由 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中查看:

image.png

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)

最后在浏览器响应:

image.png ... image.png

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('修改成功')