zoukankan      html  css  js  c++  java
  • Django一页通

    官网:https://www.djangoproject.com/,中文官方教程:https://docs.djangoproject.com/zh-hans/3.1/

    安装: pip install django 

    查看版本: django-admin --version  或: 1 import django 2 django.get_version() 

    创建工程: django-admin startproject 工程名 

    启动服务: python manage.py runserver 

    服务启动成功后浏览器访问:http://127.0.0.1:8000/

    启动服务指定端口: python manage.py runserver 8001 

    启动服务指定IP:端口: python manage.py runserver 127.0.0.1:8002 (不能只指定IP不指定端口)

    让所有人都可访问: python manage.py runserver 0.0.0.0:8000 同时需要设置settings.py中的代码 ALLOWED_HOSTS = ['*'] 

    创建应用: python manage.py startapp myapp 或 django-admin startapp appname 

    访问后台管理:http://localhost:8000/admin

    生成迁移: python manage.py makemigrations ,指定应用生成迁移 python manage.py makemigrations myapp 

    执行迁移: python manage.py migrate 


    第一个演示Demo:

    myapp/views.py

    from django.http import HttpResponse
    
    def hello(request):
        return HttpResponse('Hello')

    也能识别HTML代码: return HttpResponse('<h1>Hello</h1>') 

    mypro/urls.py

    from django.contrib import admin
    from django.urls import path
    
    from myapp import views
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('hello/',views.hello)
    ]

    启动服务后浏览器访问:http://localhost:8000/hello/


     优化上面的Demo:

     myapp/views.py不变。

    新增:myapp/urls.py:

    from django.urls import path
    from myapp import views
    
    urlpatterns = [
        path('hello/',views.hello)
    ]

    修改:mypro/urls.py:

    from django.contrib import admin
    from django.urls import path, include
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('myapp/',include('myapp.urls'))
    ]

    根路由已在mypro/settings.py中默认配置好: ROOT_URLCONF = 'mypro.urls' 

    浏览器访问:http://localhost:8000/myapp/hello/ 


     创建模型表名自动为应用名_模型名,数据库中生成的表名为 myapp_person

    from django.db import models
    
    class Person(models.Model):
        name=models.CharField(max_length=32) # CharField必须指定max_length,否则生成迁移文件时就会报错
        age=models.IntegerField(default=18) # IntegerField必须指定default,否则,新增模型正常,添加数据时报错;修改模型迁移时会阻塞并提示两种指定default值的方式

    创建模型:指定表名,数据库中生成的表名为person

    查询排序,方式一

    from django.db import models
    
    class Person(models.Model):
        name = models.CharField(max_length=32)
        age=models.IntegerField(default=18)
    
        class Meta:
            db_table = 'person' # 指定表名
            ordering='age','-name' # 指定查询时的排序规则,默认使用id排序,倒序在字段前加-,用元组或列表指定1到多个排序字段

    生成迁移文件

    (venv) D:桌面mypro>python manage.py makemigrations
    No changes detected

    原因:未注册应用,需要在mypro/mypro/settings.py中注册 INSTALLED_APPS = ['myapp'] 或 INSTALLED_APPS = ['myapp.apps.MyappConfig'] 

    再次生成迁移文件:

    (venv) D:桌面mypro>python manage.py makemigrations
    Migrations for 'myapp':
      myappmigrations001_initial.py
        - Create model Person

    执行迁移:完成后会在数据库迁移记录表中产品相应的迁移记录,并创建对应模型的表。

    (venv) D:桌面mypro>python manage.py migrate
    Operations to perform:
      Apply all migrations: admin, auth, contenttypes, myapp, sessions
    Running migrations:
      Applying myapp.0001_initial... OK

     若对模型有修改,可再次执行生成迁移文件执行迁移。

    若删除迁移文件,则一定要同时删除表中迁移记录,及删除对应模型的表。

    migrations包勿删!


    使用模板,在myapp目录中建立模板文件夹templates,注:不是template

    myapp/views.py

    渲染方式一

    from django.shortcuts import render
    
    def hello(request):
        return render(request,'hello.html')

    渲染方式二

    from django.http import HttpResponse
    from django.template import loader
    
    def hello(request):
        template=loader.get_template('hello.html')
        return HttpResponse(template.render())

    myapp/templates/hello.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <h1>标题一</h1>
    </body>
    </html>

    使用模板,在工程目录mypro中建立template或templates文件夹,并在settings.py中注册。(推荐方式)

    视图函数myapp/views.py同上不用改变。

    mypro/template/hello.html或mypro/templates/hello.html文件内容同上。

    mypro/mypro/settings.py中注册:

    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',
                ],
            },
        },
    ]

    数据库的增删改查

    ,方式一

    mypro/myapp/views.py

    from django.http import HttpResponse
    from myapp.models import Person
    
    def add(request):
        person=Person()
        person.name='李四'
        person.save()
        return HttpResponse(f'新增成功,{person.name}')

    ,方式二

    def addperson(request):
        Person.objects.create(name='李四',age=22) # 关键代码
        return HttpResponse('添加成功')

    mypro/myapp/views.py

    from django.http import HttpResponse
    from myapp.models import Person
    
    def delete(request):
        person=Person.objects.first()
        person.delete()
        return HttpResponse(f'删除成功,{person.name}')

     改

    mypro/myapp/views.py

    from django.http import HttpResponse
    from myapp.models import Person
    
    def update(request):
        person=Person.objects.first()
        person.name='王五'
        person.save()
        return HttpResponse(f'更新成功,{person.name}')

    mypro/myapp/views.py

    from django.shortcuts import render
    from myapp.models import Person
    
    def query(request):
        persons=Person.objects.all()
        context={
            'persons':persons
        }
        return render(request,'myapp/query.html',context=context)

    mypro/templates/myapp/query.html,用到了模板语法

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <ul>
        {% for person in persons %}
            <li>{{ person.name }}</li>
        {% endfor %}
    </ul>
    </body>
    </html>

    查询过滤:filter和exclude可任意多个级联

    过滤条件:__gt=、__gte=、__lt=、__lte=、__year=,其他month、day、week_day、hour、minute、second

    def getperson(request):
        persons=Person.objects.filter(age__gt=20).exclude(age__gt=30)
        context={
            'persons':persons
        }
        return render(request,'hello.html',context=context)

    = 同 __exact= 大小写敏感 persons=Person.objects.filter(name='Tom') 同 persons=Person.objects.filter(name__exact='Tom') 

    __iexact 忽略大小写  persons=Person.objects.filter(name__iexact='Tom')  i为ignore在sqlite3中以下3个有无i都一样:

    __contains同 __icontains忽略大小写 persons=Person.objects.filter(name__contains='t') 同 persons=Person.objects.filter(name__icontains='Tom') 

    __startswith同 __istartswith忽略大小写 persons=Person.objects.filter(name__startswith='t')同 persons=Person.objects.filter(name__istartswith='t') 

    __endswith同__iendswith忽略大小写persons=Person.objects.filter(name__endswith='m') 同 persons=Person.objects.filter(name__iendswith='m') 

    __isnull  persons=Person.objects.filter(name__isnull=False)  __isnull=True未试验出效果。无__isnotnull和__notisnull

    __in大小写敏感 persons=Person.objects.filter(name__in=['无名氏','Tom']) 

    __range persons=Person.objects.filter(age__range=(30,50)) 

    查询排序,方式二

    def getperson(request):
        persons=Person.objects.order_by('name')
        context={
            'persons':persons
        }
        return render(request,'hello.html',context=context)

    默认管理页面为英文,改为中文:mypro/mypro/settings.py LANGUAGE_CODE = 'zh-hans' ,再访问:http://127.0.0.1:8000/admin就显示中文。

    默认时区为  TIME_ZONE = 'UTC' 改为 TIME_ZONE = 'Asia/Shanghai' 


     自定义创建对象的类方法

    from django.db import models
    
    class Person(models.Model):
        name = models.CharField(max_length=32)
        age=models.IntegerField(default=18)
    
        @classmethod
        def create(cls,name='无名氏',age=28):
            person=cls()
            person.name=name
            person.age=age
            person.save()
    
        class Meta:
            db_table = 'person'
            ordering='age','-name'

    创建对象

    ,方式三

    def addperson(request):
        Person.create()
        Person.create(name='小猪')
        Person.create(age=29)
        Person.create(name='小狗',age=21)
        return HttpResponse('添加成功')

     将查询结果集中的对象转化为字典,values()

    def getperson(request):
        persons=Person.objects.order_by('name')
        print('-----------------------')
        print(type(persons))
        print('-----------------------')
        print(persons)
        print('-----------------------')
        print(persons.values())
        print('-----------------------')
        print(list(persons.values())) # 关键代码
        print('-----------------------')
        context={
            'persons':persons
        }
        return render(request,'hello.html',context=context)

    查询单个数据

    get()

    def getperson(request):
        # 多个会报MultipleObjectsReturned
        # 未查询到数据会报DoesNotExist
        person=Person.objects.get(name='李四')
        print('-----------------------')
        print(type(person)) # <class 'myapp.models.Person'>
        print('-----------------------')
        print(person) # Person object (301)
        print('-----------------------')
        return HttpResponse(f'查询成功,姓名={person.name}')

     first()

    def getperson(request):
        person=Person.objects.first() # first()无参数
        print('-----------------------')
        print(type(person)) # <class 'myapp.models.Person'>
        print('-----------------------')
        print(person) # Person object (239)
        print('-----------------------')
        return HttpResponse(f'查询成功,姓名={person.name}')

     last()

    def getperson(request):
        person=Person.objects.last()
        return HttpResponse(f'查询成功,姓名={person.name}')

    查询计数,统计查询结果集,count()

    def getperson(request):
        persons=Person.objects.all()
        return HttpResponse(f'查询成功,{persons.count()}个人。')

    判断查询结果集是否有数据,exists()

    def getperson(request):
        persons=Person.objects.filter(name='李四')
        if persons.exists():
            return HttpResponse('查询成功')
        return HttpResponse('查询失败')

    通过主键查询,pk=xxx,id=xxx

     persons=Person.objects.filter(pk=308) 或 persons=Person.objects.filter(id=306) 


     约束:唯一约束,unique=True,默认False

    class User(models.Model):
        name=models.CharField(max_length=16,unique=True)

    添加重复记录会报IntegrityError完整性错误,UNIQUE constraint failed: myapp_user.name唯一约束失败


    限制查询结果集,类似字符串或列表的切片,但下标不能为负

    def getperson(request):
        persons=Person.objects.all()[2:4] # 跳过第0、1个,取第2、3个,左闭右开
        context={
            'persons':persons
        }
        return render(request,'hello.html',context=context)

     分页查看,get请求传参数,方式一

    def getperson(request):
        page=int(request.GET.get('page')) # get请求传参,关键代码
        per_page=5
        persons=Person.objects.all()[(page-1)*per_page:page*per_page] # 分页,关键代码
        context={
            'persons':persons
        }
        return render(request,'hello.html',context=context)

    浏览器访问:http://127.0.0.1:8000/myapp/getperson/?page=2


    分页器

    views.py

    def getinfo(request):
        p=int(request.GET.get('p',1))
        notices=Notice.objects.all()
        paginator=Paginator(notices,10) # 每页10条数据
        print(f'总记录数={paginator.count}')
        print(f'总页数={paginator.num_pages}')
        print(f'页码列表={paginator.page_range}')
        page=paginator.page(p)
        print(f'当前页数据对象={page.object_list}')
        print(f'当前页码值={page.number}')
        print(f'当前页的Paginator对象={page.paginator}')
        print(f'是否有下一页:{page.has_next()}')
        print(f'是否有上一页:{page.has_previous()}')
        print(f'是否有上一页或下一页:{page.has_other_pages()}')
        print(f'下一页页码:{page.next_page_number()}')
        print(f'上一页页码:{page.previous_page_number()}')
        print(f'当前页数据数:{len(page)}')
        return render(request,'info.html',locals())

    urls.py  path('getinfo/',views.getinfo), 

    models.py

    class Notice(models.Model):
        info=models.CharField(max_length=16)
    models.py

    info.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>分页信息</title>
    </head>
    <body>
        <ul>
            {% for notice in page %}
            <li>{{ notice.info }}</li>
            {% endfor %}
        </ul>
    </body>
    </html>

    get请求传参数,方式二

     urls.py  path('hi/<int:num>/<str:name>/',views.hi) 

    views.py

    def hi(request,num,name):
        print(type(num)) # <class 'int'>
        print(num) # 666
        print(type(name)) # <class 'str'>
        print(name) # good
        return HttpResponse('hi')

    浏览器访问:http://127.0.0.1:8000/myapp/hi/666/good/


     数据级联

    一对多

    models.py

    class User(models.Model):
        name=models.CharField(max_length=16,unique=True)
    
    class Good(models.Model):
        name=models.CharField(max_length=16)
        user=models.ForeignKey(User,on_delete=models.CASCADE) # 一定要设置on_delete,否则生成迁移文件时会报错

    views.py

    def adduser(request):
        user=User()
        user.name='黄牛'
        user.save()
        return HttpResponse(f'添加User成功,{user.name}')
    
    def addgood(request):
        user=User.objects.last()
        good=Good()
        good.name='泉水'
        good.user=user
        good.save()
        return HttpResponse(f'添加货物成功:{good.name},{good.user.name}')
    
    def getgood(request):
        user=User.objects.last()
        # goods=Good.objects.filter(user=user)
        goods=user.good_set.all()
        return render(request,'goods.html',context=locals())

    goods.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>货物清单</title>
    </head>
    <body>
        <ul>
            {% for good in goods %}
                <li>{{ good.name }} - {{ good.user.name }}</li>
            {% endfor %}
        </ul>
    </body>
    </html>

     跨关系查询,数据去重

    models.py

    class Author(models.Model):
        name=models.CharField(max_length=16)
    
    class Article(models.Model):
        content=models.TextField() # 可不带参数
        author=models.ForeignKey(Author,on_delete=models.CASCADE)

    views.py

    def getauthor(request):
        # 不能写成Article__content__contains,即模型名在此必须全小写
        # 规则:模型类名__属性名__比较运算符=
        authors=Author.objects.filter(article__content__contains='黄山') # 关键代码,跨关系查询
        # 不支持distinct操作,下面这行会报错:
        # authors=Author.objects.filter(article__content__contains='黄山').distinct('name')
        author_list=[]
        for author in authors: # 关键代码,数据去重
            if author not in author_list:
                author_list.append(author)
        return render(request,'authors.html',context=locals())

    authors.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>作者清单</title>
    </head>
    <body>
        <ul>
            {% for author in author_list %}
                <li>{{ author.name }}</li>
            {% endfor %}
        </ul>
    </body>
    </html>
    authors.html

     聚合、自相关查询、F/Q对象、显隐属性

    models.py

    class Student(models.Model):
        # 主键未指定会自动产生id,为隐式属性;若指定,则不会自动产生,为显式属性
        sno=models.AutoField(primary_key=True) # 关键代码
        name=models.CharField(max_length=16)
        python=models.IntegerField(default=0)
        linux=models.IntegerField(default=0)

    views.py

    def getstudent(request):
       # 聚合
    # result=Student.objects.aggregate(Avg('python')) # 平均值={'python__avg': 84.2} # result=Student.objects.aggregate(Count('python')) # 计数={'python__count': 5} # result=Student.objects.aggregate(Max('python')) # 最大值={'python__max': 99} # result=Student.objects.aggregate(Min('python')) # 最小值={'python__min': 70} # result=Student.objects.aggregate(Sum('python')) # 最小值={'python__sum': 418} # return HttpResponse(f'查询成功:{result}') # F对象的应用:行(记录)自相关查询 # students=Student.objects.filter(python__gt=F('linux')) # students=Student.objects.filter(python__gt=F('linux')+5) # Q对象的应用:组合条件查询,与&、或|、非~ # students=Student.objects.filter(Q(python__gt=80) & Q(linux__gt=80)) # students=Student.objects.filter(Q(python__gt=80) | Q(linux__gt=80)) students=Student.objects.filter(~Q(Q(python__gt=80) | Q(linux__gt=80))) return render(request,'students.html',locals())

    students.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>学生成绩清单</title>
    </head>
    <body>
        <ul>
            {% for student in students %}
                <li>学号={{ student.sno }},姓名={{ student.name }},Python={{ student.python }},Linux={{ student.linux }}</li>
            {% endfor %}
        </ul>
    </body>
    </html>
    students.html

     自定义模型管理器

    models.py

    class TeacherManager(models.Manager):
        pass
    
    class Teacher(models.Model):
        name=models.CharField(max_length=16)
        # teacherManager=models.Manager() # 自定义模型管理器,方式一
        teacherManager=TeacherManager() # 自定义模型管理器,方式二

    views.py

    def getteacher(request):
        # 模型管理器objects为隐性属性,未指定时会自动生成。
        # teacher=Teacher.objects.first()
        # 若自定义模型管理器teacherManager,则objects就不存在了
        teacher=Teacher.teacherManager.first()
        return HttpResponse(f'获取老师成功:{teacher.name}')

     逻辑删除

    models.py

    class TeacherManager(models.Manager):
        def get_queryset(self):
            return super().get_queryset().filter(is_delete=False)
    
    class Teacher(models.Model):
        name=models.CharField(max_length=16)
        is_delete=models.BooleanField(default=False) # 逻辑删除字段
    
        teacherManager=TeacherManager() # 实际逻辑删除后的查询集,方式二

    views.py

    def getteachers(request):
        # 实际逻辑删除后的查询集,方式一
        # teachers=Teacher.objects.filter(is_delete=False)
    
        # 实际逻辑删除后的查询集,方式二
        teachers=Teacher.teacherManager.all()
    
        return render(request,'teachers.html',locals())

     批量添加数据,此法不适合多表级联

    models.py

    class Teacher(models.Model):
        name=models.CharField(max_length=16)

    views.py

    def addteacher(request):
        teachers=[]
        for i in range(5):
            teacher=Teacher()
            teacher.name='李四{}'.format(i)
            # teacher.save() # 批量添加时不建议用save(),因为save()会频繁的建立/关闭数据库连接
            teachers.append(teacher)
        Teacher.objects.bulk_create(teachers) # 批量添加时的建议方法
        return HttpResponse(f'添加老师成功:{teachers}')

      一对一,1:1,多表数据级联操作

     models.py

    class IDCard(models.Model):
        idno=models.CharField(max_length=32,unique=True)
    
    class Phone(models.Model):
        phoneno=models.CharField(max_length=16)
    
        # CASCADE:删除IDCard会自动删除Phone,删除Phone不会删除IDCard
        # idcard=models.OneToOneField(IDCard,on_delete=models.CASCADE) # 使用外键+唯一约束实现一对一关系
    
        # PROTECT:删IDCard前必须先删Phone
        idcard=models.OneToOneField(IDCard,on_delete=models.PROTECT)
    
        # SET_NULL:前提是此字段可为空,否则无法设置。
        # idcard=models.OneToOneField(IDCard,null=True,on_delete=models.SET_NULL)
    
        # SET_DEFAULT:前提是此字段必须设置默认值,且默认值的数据类型要正确,且未被其他对象关联。
        # idcard=models.OneToOneField(IDCard,default=4,on_delete=models.SET_DEFAULT)
    
        # 前提是设置的值(如666)要存在,且未被其他对象关联。
        # idcard=models.OneToOneField(IDCard,default=4,on_delete=models.SET(666))

    views.py

    def addidcard(request):
        idcard=IDCard()
        idcard.idno='x002'
        idcard.save()
        return HttpResponse(f'添加身份证成功:{idcard.idno}')
    
    def addphone(request):
        idcard=IDCard.objects.last()
        phone=Phone()
        phone.phoneno='132'
        phone.idcard=idcard
        phone.save()
        return HttpResponse(f'添加手机号成功:{phone.phoneno}')
    
    def delidcard(request):
        idcard=IDCard.objects.first()
        idcard.delete()
        return HttpResponse(f'删除身份证成功:{idcard.idno}')
    
    def delphone(request):
        phone=Phone.objects.first()
        phone.delete()
        return HttpResponse(f'删除手机号成功:{phone.phoneno}')

     主从表数据获取

    views.py

    def get_idcard_by_phone(request):
        phone=Phone.objects.first()
        # idcard为Phone的显性属性
        idcard=phone.idcard
        return HttpResponse(f'通过手机号:{phone.phoneno},获取身份证:{idcard.idno}成功。')
    
    def get_phone_by_idcard(request):
        idcard=IDCard.objects.last()
        # 主表获取从表通过隐性属性,即从表名小写
        # phone为IDCard的隐性属性
        phone=idcard.phone
        return HttpResponse(f'通过身份证:{idcard.idno},获取手机号:{phone.phoneno}成功。')

    一对多,1:N

    models.py

    class Province(models.Model):
        name=models.CharField(max_length=16)
    
    class City(models.Model):
        name=models.CharField(max_length=16)
        province=models.ForeignKey(Province,on_delete=models.PROTECT) # 一对多通过外键实现

    views.py

    def get_province_by_city(request):
        city=City.objects.first()
        province=city.province # 显性属性
        return HttpResponse(f'通过城市:{city.name},获取省:{province.name}成功。')
    
    def get_citys_by_province(request):
        province=Province.objects.last()
        cities=province.city_set.all() # city_set为Province的隐性属性
        return render(request,'cities.html',locals())

    添加数据:

    def add_city(request):
        province=Province.objects.last()
        city=City()
        city.name='常州'
        # city.province=province # 方式一
        city.save()
        province.city_set.add(city) # 方式二,前提是city的外键省字段province可为空,即province=models.ForeignKey(Province,null=True,on_delete=models.PROTECT)
     return HttpResponse(f'给省:{province.name}添加城市:{city.name},成功!')

    一对多数据删除同一对一


     多对多,M:N,由于会创建额外的关系表,所以哪个表申明关系不像一对一和一对多那样很介意了。

    models.py

    class Reader(models.Model):
        name=models.CharField(max_length=16) # 更重要的设为主表
    
    class News(models.Model):
        content=models.TextField()
       # 次重要的申明关系,设为从表 reader
    =models.ManyToManyField(Reader) # 会自动创建额外的关系表维护多对多关系

    views.py

    def add_reader(request):
        reader=Reader()
        reader.name='王五'
        reader.save()
        return HttpResponse(f'添加读者成功,{reader.name}')
    
    def add_news(request):
        news=News()
        news.content='劳动法将严格执行'
        news.save()
        return HttpResponse(f'添加新闻成功,{news.content}')
    
    def add_reader_news(request):
        reader=Reader.objects.last()
        news=News.objects.last()
    
        # news.reader.add(reader) # 多对多关系绑定,方式一,从表的显性属性绑定
        reader.news_set.add(news) # 多对多关系绽定,方式二,主表的隐性属性绑定。是否有remove、clear等方法?
    
        return HttpResponse(f'添加读者-新闻关系成功,{reader.name},{news.content}')

     模型继承

    models.py

    class Animal(models.Model):
        name=models.CharField(max_length=16)
        
        # 这种写法更好,只创建Dog一张表,单表的性能更好。否则会创建Animal和Dog两张表,多表级联会降低性能。
        class Meta:
            abstract=True
    
    class Dog(Animal):
        color=models.CharField(max_length=16)

    T 模板语法

    countrys.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>幸福国信息</title>
    </head>
    <body>
    <h6>{{ countrys.0.name }}</h6> {# 索引属性 #}
    <h6>{{ countrys.1.develop }}</h6> {# 方法,不能传参 #}
    <h6>{{ provinces.安徽 }}</h6> {# 字典的键 #}
    {# 单行注释 #}
    {% comment %}
        多行注释
    {% endcomment %}
    <!--
        不建议用HTML的注释,能在浏览器查看源码中显示。
    -->
    <ul>
        {% for country in countrys %}
        {% if forloop.first %}
        <li style="color:#ff0000">{{forloop.counter0}} {{ country.name }}</li>
        {% elif forloop.last %}
        <li style="color:#0f0">{{forloop.counter}} {{ country.name }}</li>
        {% else %}
        <li>{{ forloop.revcounter0 }} {{ country.name }} {{ forloop.revcounter }}</li>
        {% endif %}
    
        {% empty %}
        <h2>for循环为空</h2>
        {% endfor %}
    </ul>
    </body>
    </html>

    models.py

    class Country(models.Model):
        name=models.CharField(max_length=16)
        def develop(self):
            return '杀贪官、斩奸商!人民幸福!人人爱国敬业诚信友善!'
    models.py

    views.py

    def getcountrys(request):
        countrys=Country.objects.all()
        provinces={
            '安徽':'合肥',
            '江苏':'南京',
        }
        return render(request,'countrys.html',locals())
    views.py

     T 模板语法 继续

    index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>模板语法</title>
        <script type="text/javascript">
            alert('网站崩溃了!')
        </script>
    </head>
    <body>
    {% widthratio 5 1 2 %} {# 数 分母 分子 #}
    <hr>
    <ul>
        {% for name in names %}
        {% if forloop.counter|divisibleby:2 %} {# 整除 #}
        <li style="color:red">{{name}}</li>
        {% else %}
        <li style="color:blue">{{name}}</li>
        {% endif %}
        {% endfor %}
    </ul>
    <hr>
        {% for name in names %}
            {% ifequal name 'Tom' %}
                <li>{{name}}</li>
            {% endifequal %}
    
            {% ifnotequal name "Tom" %}
                <li>{{name}}</li>
            {% endifnotequal %}
        {% endfor %}
    <hr>
    {{5|add:10}}
    {{10|add:-5}}
    {{'Tom'|lower}}
    {{"Tom"|upper}}
    <hr>
    {{names|join:'-'}}
    <hr>
    {{var|default:'中国'}}
    <hr>
    {{dateVal|date:'y-m-d'}}
    <hr>
    {{code|safe}}
    <hr>
    {% autoescape off %}
        {{code}}
    {% endautoescape %}
    <hr>
    {% autoescape on %}
        {{code}}
    {% endautoescape %}
    </body>
    </html>

    views.py

    def index(request):
        names=['Tom','Jerry']
        dateVal=datetime.now()
    
        # code='<h1>好好学习</h1>'
    
        # code='''
        #     <script type="text/javascript">
        #     alert('网站崩溃了!')
        #     </script>
        # '''
    
        code='''
            <script type="text/javascript">
                window.onload=function(){
                    var lis=document.getElementsByTagName("li");
                    for(var i=0;i<lis.length;i++){
                        console.log(i);
                        lis[i].innerHTML="你的网站崩溃了!";
                    }
                }
            </script>
        '''
        return render(request,'index.html',locals())

     结构标签,block+extends,化整为零,推荐使用

    base.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>{{Title}}</title>
    
        {% block extJS %}
        {% endblock %}
    
        {% block extCSS%}
        {% endblock %}
    </head>
    <body>
    
    {% block header %}
    {# 首次出现为定义 #}
    {% endblock %}
    
    {% block banner %}
    {% endblock %}
    
    {% block content %}
    {% endblock %}
    
    {% block footer %}
    {% endblock %}
    
    </body>
    </html>

    loginBase.html

    {% extends 'base.html' %}
    
    {% block header %}
    <h1>再次出现为重写</h1>
    {% endblock %}
    
    {% block logininfo %} {# 继承之后再次挖坑,后面的继承此坑不生效 #}
    {% endblock %}

    login.html

    {% extends 'loginBase.html' %}
    
    {% block header %}
    {{ block.super }} {# 调用父类后面就为追加 #}
    <h2>三次及以上出现为覆盖之前的重写</h2>
    {% endblock %}
    
    {% block logininfo %} {# 未生效 #}
    <h3>这是登录信息</h3>
    {% endblock %}
    
    {% block banner %}
    <h4>这是轮播</h4>
    {% endblock %}
    
    {% block content %}
    <h5>这是内容</h5>
    {% endblock %}
    
    {% block footer %}
    <h6>这是底部信息</h6>
    {% endblock %}

    views.py

    def login(request):
        title='结构标签'
        return render(request,'login.html',locals())

    结构标签,include,聚零为整,不推荐使用,性能差

     first.html

    <h1>这是first.html的内容</h1>

    second.html

    <h2>这是second.html的内容</h2>

    all.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>{{title}}</title>
    </head>
    <body>
        {% include 'first.html' %}
        {% include 'second.html' %}
    </body>
    </html>

    views.py

    def all(request):
        title='结构标签include'
        return render(request,'all.html',locals())

    响应json数据

    views.py

    def getJson(request):
        data={
            'status':0,
            'msg':'ok'
        }
        return JsonResponse(data)

    urls.py  path('getJson',views.getJson), 


     页面跳转

    hi_info.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>页面跳转</title>
    </head>
    <body>
    <a href="/myapp/hi">跳转到hi页</a>
    </body>
    </html>

    views.py

    def hi_info(request):
        return render(request,'hi_info.html')
    
    def hi(request):
        return HttpResponse('hi')

    urls.py  path('hi_info',views.hi_info), 、 path('hi',views.hi) 和 path('hi/',views.hi) 有区别,注:路径后是否以/结尾有区别


     自定义404页面未找到,Page not found (404)

    直接在templates目录中创建404.html

    404.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>页面未找到</title>
    </head>
    <body>
    页面未找到
    </body>
    </html>

    设置settings.py  DEBUG = False 和 ALLOWED_HOSTS = ['*'] ,ALLOWED_HOSTS不为空就好。


    HttpRequest对象

    views.py

    def hi(request,num,name):
        print('----------------')
        print(request) # <WSGIRequest: GET '/myapp/hi/666/good/?key=%27%E4%B8%AD%E5%9B%BD%27'>
        print(request.path) # /myapp/hi/666/good/
        print(request.method) # GET
        print(request.encoding) # None
        print(request.GET) # <QueryDict: {'key': ["'中国'"]}>
        print(request.POST) # <QueryDict: {}>
        print(request.FILES) # <MultiValueDict: {}>
        print(request.COOKIES) # {'csrftoken': 'QybCRghQbKBAaZ7FHsiYWVWTukk6h940GssD4Tt8YRLk3XAfJZ77mWGrZp8Vz9gh'}
        print(request.session) # <django.contrib.sessions.backends.db.SessionStore object at 0x000002E36FCFE3A0>
        print(request.is_ajax()) # False
        print('################')
        print(request.META)
        print('----------------')
        return HttpResponse('hi')

    urls.py  path('hi/<int:num>/<str:name>/',views.hi) 

    浏览器访问:http://127.0.0.1:8000/myapp/hi/666/good/?key='中国'

     request.META 好多重要信息都在这里面!

    {'PUBLIC': 'C:\Users\Public', 'LOCALAPPDATA': 'C:\Users\xiongjiawei\AppData\Local', 'PROGRAMFILES': 'C:\Program Files', 'VIRTUAL_ENV': 'D:\妗岄
    潰\mypro\venv', 'USERNAME': 'xiongjiawei', 'COMMONPROGRAMW6432': 'C:\Program Files\Common Files', 'LG_PATH': 'D:\Program Files (x86)\HP\LoadRunne
    r\', 'IDEA_INITIAL_DIRECTORY': 'C:\Program Files\JetBrains\PyCharm 2020.1\bin', 'NUMBER_OF_PROCESSORS': '4', 'PROCESSOR_ARCHITECTURE': 'AMD64', 'PR
    OMPT': '(venv) $P$G', '__INTELLIJ_COMMAND_HISTFILE__': 'C:\Users\xiongjiawei\AppData\Roaming\JetBrains\PyCharm2020.1\terminal\history\history-1
    ', 'SYSTEMDRIVE': 'C:', 'CONFIGSETROOT': 'C:\WINDOWS\ConfigSetRoot', 'CLASSPATH': 'C:\Program Files\Java\jdk1.8.0_131\lib\dt.jar;C:\Program File
    s\Java\jdk1.8.0_131\lib\tools.jar', 'PROGRAMDATA': 'C:\ProgramData', 'PROCESSOR_REVISION': '8e09', 'COMMONPROGRAMFILES(X86)': 'C:\Program Files (x
    86)\Common Files', 'USERPROFILE': 'C:\Users\xiongjiawei', 'ANALYSIS_PATH': 'D:\Program Files (x86)\HP\LoadRunner\', '_OLD_VIRTUAL_PATH': 'D:\app
    \xiongjiawei\product\11.2.0\dbhome_1\bin;C:\ProgramData\Oracle\Java\javapath;C:\Program Files (x86)\Intel\iCLS Client\;C:\Program Files\I
    ntel\iCLS Client\;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files (x8
    6)\Intel\Intel(R) Management Engine Components\DAL;C:\Program Files\Intel\Intel(R) Management Engine Components\DAL;C:\Program Files (x86)\Inte
    l\Intel(R) Management Engine Components\IPT;C:\Program Files\Intel\Intel(R) Management Engine Components\IPT;C:\Program Files (x86)\NVIDIA Corpo
    ration\PhysX\Common;D:\Program Files\TortoiseSVN\bin;D:\Users\xiongjiawei\AppData\Local\Android\sdk\platform-tools;D:\Program Files\VanDyk
    e Software\Clients\;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;D:\Program Files (
    x86)\Appium\node_modules\.bin;D:\Program Files\nodejs\;D:\Program Files\android-sdk-windows\tools;C:\Program Files\Java\jdk1.8.0_131\bin;D:
    \Program Files\android-sdk-windows\platform-tools;C:\Program Files\Java\jdk1.8.0_131\jre\bin;C:\WINDOWS\System32\OpenSSH\;d:\Program Files
    (x86)\Tesseract-OCR;d:\Program Files\Git\cmd;D:\Program Files\Python\Python38\Scripts\;D:\Program Files\Python\Python38\;C:\Users\xiongji
    awei\AppData\Local\Microsoft\WindowsApps;C:\Users\xiongjiawei\AppData\Roaming\npm;%PyCharm Community Edition%;D:\Program Files (x86)\Tesserac
    t-OCR;', 'USERDOMAIN': 'LAPTOP-BAIQPBL2', 'PSMODULEPATH': 'C:\Program Files\WindowsPowerShell\Modules;C:\WINDOWS\system32\WindowsPowerShell\v1.0
    Modules', 'PROCESSOR_LEVEL': '6', 'TEMP': 'C:\Users\XIONGJ~1\AppData\Local\Temp', 'PROGRAMW6432': 'C:\Program Files', 'TESSDATA_PREFIX': 'd:\Pro
    gram Files (x86)\Tesseract-OCR\', 'APPDATA': 'C:\Users\xiongjiawei\AppData\Roaming', 'LOGONSERVER': '\\LAPTOP-BAIQPBL2', 'JAVA_HOME': 'C:\Progr
    am Files\Java\jdk1.8.0_131', 'PATHEXT': '.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC', 'TERMINAL_EMULATOR': 'JetBrains-JediTerm', 'LR_PATH':
     'D:\Program Files (x86)\HP\LoadRunner\', 'WINDIR': 'C:\WINDOWS', '_OLD_VIRTUAL_PROMPT': '$P$G', 'SYSTEMROOT': 'C:\WINDOWS', 'COMPUTERNAME': 'LAPT
    OP-BAIQPBL2', 'SESSIONNAME': 'Console', 'PROGRAMFILES(X86)': 'C:\Program Files (x86)', 'PROCESSOR_IDENTIFIER': 'Intel64 Family 6 Model 142 Stepping 9,
    GenuineIntel', 'HOMEPATH': '\Users\xiongjiawei', 'DRIVERDATA': 'C:\Windows\System32\Drivers\DriverData', 'VUGEN_PATH': 'D:\Program Files (x86)\H
    P\LoadRunner\', 'TMP': 'C:\Users\XIONGJ~1\AppData\Local\Temp', 'COMSPEC': 'C:\WINDOWS\system32\cmd.exe', 'ALLUSERSPROFILE': 'C:\ProgramData',
     'PATH': 'D:\妗岄潰\mypro\venv\Scripts;D:\app\xiongjiawei\product\11.2.0\dbhome_1\bin;C:\ProgramData\Oracle\Java\javapath;C:\Program File
    s (x86)\Intel\iCLS Client\;C:\Program Files\Intel\iCLS Client\;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System3
    2\WindowsPowerShell\v1.0\;C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\DAL;C:\Program Files\Intel\Intel(R) Management En
    gine Components\DAL;C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\IPT;C:\Program Files\Intel\Intel(R) Management Engine Com
    ponents\IPT;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;D:\Program Files\TortoiseSVN\bin;D:\Users\xiongjiawei\AppData\Local\Andr
    oid\sdk\platform-tools;D:\Program Files\VanDyke Software\Clients\;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\Syste
    m32\WindowsPowerShell\v1.0\;D:\Program Files (x86)\Appium\node_modules\.bin;D:\Program Files\nodejs\;D:\Program Files\android-sdk-windows\t
    ools;C:\Program Files\Java\jdk1.8.0_131\bin;D:\Program Files\android-sdk-windows\platform-tools;C:\Program Files\Java\jdk1.8.0_131\jre\bin;C
    :\WINDOWS\System32\OpenSSH\;d:\Program Files (x86)\Tesseract-OCR;d:\Program Files\Git\cmd;D:\Program Files\Python\Python38\Scripts\;D:\Pr
    ogram Files\Python\Python38\;C:\Users\xiongjiawei\AppData\Local\Microsoft\WindowsApps;C:\Users\xiongjiawei\AppData\Roaming\npm;%PyCharm Co
    mmunity Edition%;D:\Program Files (x86)\Tesseract-OCR;', 'ANDROID_HOME': 'D:\Program Files\android-sdk-windows', 'HOMEDRIVE': 'C:', 'COMMONPROGRAMFI
    LES': 'C:\Program Files\Common Files', 'ONEDRIVE': 'C:\Users\xiongjiawei\OneDrive', 'USERDOMAIN_ROAMINGPROFILE': 'LAPTOP-BAIQPBL2', 'OS': 'Windows_
    NT', 'LOG_FILE': 'C:\Users\xiongjiawei\AppData\Local\Temp\ihp_custom_batches.log', 'DJANGO_SETTINGS_MODULE': 'mypro.settings', 'RUN_MAIN': 'true',
     'SERVER_NAME': 'LAPTOP-BAIQPBL2', 'GATEWAY_INTERFACE': 'CGI/1.1', 'SERVER_PORT': '8000', 'REMOTE_HOST': '', 'CONTENT_LENGTH': '', 'SCRIPT_NAME': '', 'S
    ERVER_PROTOCOL': 'HTTP/1.1', 'SERVER_SOFTWARE': 'WSGIServer/0.2', 'REQUEST_METHOD': 'GET', 'PATH_INFO': '/myapp/hi/666/good/', 'QUERY_STRING': 'key=%27%
    E4%B8%AD%E5%9B%BD%27', 'REMOTE_ADDR': '127.0.0.1', 'CONTENT_TYPE': 'text/plain', 'HTTP_HOST': '127.0.0.1:8000', 'HTTP_CONNECTION': 'keep-alive', 'HTTP_C
    ACHE_CONTROL': 'max-age=0', 'HTTP_UPGRADE_INSECURE_REQUESTS': '1', 'HTTP_USER_AGENT': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHT
    ML, like Gecko) Chrome/85.0.4183.121 Safari/537.36', 'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/a
    png,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', 'HTTP_SEC_FETCH_SITE': 'none', 'HTTP_SEC_FETCH_MODE': 'navigate', 'HTTP_SEC_FETCH_USER': '?1', 'H
    TTP_SEC_FETCH_DEST': 'document', 'HTTP_ACCEPT_ENCODING': 'gzip, deflate, br', 'HTTP_ACCEPT_LANGUAGE': 'zh-CN,zh;q=0.9', 'HTTP_COOKIE': 'csrftoken=QybCRg
    hQbKBAaZ7FHsiYWVWTukk6h940GssD4Tt8YRLk3XAfJZ77mWGrZp8Vz9gh', 'wsgi.input': <django.core.handlers.wsgi.LimitedStream object at 0x000002B0A8BD3E20>, 'wsgi
    .errors': <_io.TextIOWrapper name='<stderr>' mode='w' encoding='utf-8'>, 'wsgi.version': (1, 0), 'wsgi.run_once': False, 'wsgi.url_scheme': 'http', 'wsg
    i.multithread': True, 'wsgi.multiprocess': False, 'wsgi.file_wrapper': <class 'wsgiref.util.FileWrapper'>, 'CSRF_COOKIE': 'QybCRghQbKBAaZ7FHsiYWVWTukk6h
    940GssD4Tt8YRLk3XAfJZ77mWGrZp8Vz9gh'}
    View Code

    get请求传递多个同名参数获取方式:

     views.py

    def hi(request,num,name):
        print('----------------')
        print(request.GET.get('name')) # xyz
        print(request.GET['name']) # xyz
        print(request.GET.getlist('name')) # ['abc', 'xyz']
        print(request.GET.get('notexist')) # None
        print(request.GET.getlist('notexist')) # []
        print('----------------')
        return HttpResponse('hi')

    浏览器访问:http://127.0.0.1:8000/myapp/hi/666/good/?name=abc&name=xyz


     POST请求

    CSRF验证失败,解决方式一:注释掉settiings中的相应代码 'django.middleware.csrf.CsrfViewMiddleware' 

    login.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>登录</title>
    </head>
    <body>
    <form action="/myapp/login/" method="post">
        {% csrf_token %} {# CSRF验证失败,解决方式二 #}
    <!--    <input type="hidden" name="csrfmiddlewaretoken" value="DFXxHTfWPbUlw37XwtuJAj4wh7EXGLSKtzeyUwreCi45p1Axy0jS0kO4McsMYL41">-->
        {# 若不写name,则request.POST为空 #}
        <input type="text" placeholder="请输入账号" name="username">
        <input type="password" placeholder="请输入密码" name="password">
    <!--    <button>登录</button>--> {# 登录按钮写法一 #}
        <input type="submit" value="登录"> {# 登录按钮写法二 #}
    </form>
    </body>
    </html>

    views.py

    def login(request):
        if request.method=='GET':
            return render(request,'login.html')
        elif request.method=='POST':
            # login.html中账号和密码未写name则为<QueryDict: {}>
            # 写了name为<QueryDict: {'username': ['111'], 'password': ['222']}>
            print(request.POST) # 获取其中具体的值同request.GET
            return HttpResponse('登录成功')

    HttpResponseJsonResponse

    views.py

    def getresponse(request):
        # Content-Type: text/html
        response=HttpResponse()
        response.content=''
        response.content='' # 覆盖
        response.write('') # 追加
        response.write('') # 还是追加
        response.flush()
    
        # Content-Type: application/json
        # response=JsonResponse({'country':'中国'})
        return response

     重定向

    views.py

    def first(request):
        # return HttpResponse('first')
        return HttpResponseRedirect('/myapp/second/') # 重定向,方式一
        # return redirect('/myapp/second') # 重定向,方式二
    
    def second(request):
        return HttpResponse('second')

    urls.py

    path('first/',views.first),
    path('second/',views.second),

    会话技术

    Cookie客户端会话技术

     views.py

    def login(request):
        if request.method=='GET':
            return render(request,'login.html')
        elif request.method=='POST':
            username=request.POST.get('username')
            password=request.POST.get('password')
            response=redirect('/myapp/mine/')
            # Cookie是服务器设置给客户端的,通过response实现
            # Cookie不支持中文,可通过存时编码,取时解码实现。
            username=base64.standard_b64encode(username.encode('utf8')).decode('utf8')
            password=base64.standard_b64encode(password.encode('utf8')).decode('utf8')
            # response.set_cookie('username',username)
            # response.set_cookie('password',password)
            # response.set_signed_cookie('username',username,'salt')
            # response.set_signed_cookie('password',password,'salt')
            # response.set_signed_cookie('username',username,SECRET_KEY)
            # response.set_signed_cookie('password',password,SECRET_KEY)
            # 设置过期时间max_age单位秒,0表示浏览器关闭失效。
            # expires单位秒,还支持timedelta(days=1),1天后过期
            response.set_signed_cookie('username',username,SECRET_KEY,max_age=60)
            response.set_signed_cookie('password',password,SECRET_KEY,expires=timedelta(days=1))
            return response
    
    def mine(request):
        # 在请求时Cookie自动被携带,Cookie不能跨浏览器,且IP(域名)隔离
        # username=request.COOKIES.get('username')
        # password=request.COOKIES.get('password')
        try:
            # username=request.get_signed_cookie('username',salt='salt')
            # password=request.get_signed_cookie('password',salt='salt')
            username=request.get_signed_cookie('username',salt=SECRET_KEY)
            password=request.get_signed_cookie('password',salt=SECRET_KEY)
            username=base64.standard_b64decode(username.encode('utf8')).decode('utf8')
            password=base64.standard_b64decode(password.encode('utf8')).decode('utf8')
        except:
            username=password=None
        print('username=',username)
    
        # 写法一
        # if username and password:
        #     return HttpResponse('个人中心')
        # return HttpResponse('游客')
    
        # 写法二
        return render(request,'mine.html',locals())
    
    def logout(request):
        response=HttpResponse('退出登录')
        response.delete_cookie('username')
        response.delete_cookie('password')
        return response

    login.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>登录</title>
    </head>
    <body>
    <form action="/myapp/login/" method="post">
        {% csrf_token %}
        <input type="text" placeholder="请输入账号" name="username">
        <input type="password" placeholder="请输入密码" name="password">
        <button>登录</button>
    </form>
    </body>
    </html>

    mine.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>个人中心</title>
    </head>
    <body>
        {% if username %}
            <h1>欢迎:{{ username }}</h1>
            <a href="/myapp/logout/">退出</a>
        {% else %}
            <h2>游客</h2>
            <a href="/myapp/login/">登录</a>
        {% endif %}
    </body>
    </html>

    urls.py

        path('login/',views.login),
        path('mine/',views.mine),
        path('logout/',views.logout),

    session服务端会话技术

    views.py

    def login(request):
        if request.method=='GET':
            return render(request,'login.html')
        elif request.method=='POST':
            username=request.POST.get('username')
            password=request.POST.get('password')
            response=redirect('/myapp/mine/')
    
            # 支持中文,默认用base64编码/解码
            request.session['username']=username
            request.session['password']=password
    
            return response
    
    def mine(request):
        username=request.session.get('username')
        password=request.session.get('password')
    
        # 写法一
        # if username and password:
        #     return HttpResponse('个人中心')
        # return HttpResponse('游客')
    
        # 写法二
        return render(request,'mine.html',locals())
    
    def logout(request):
        response=HttpResponse('退出登录')
    
        # 退出会话,方式一,不会同步删除django_session表中的session会话记录
        # response.delete_cookie('sessionid')
    
        # 退出会话,方式二,本质是将django_session表中的session会话记录的session_data字段中关于用户信息的数据置空{}
        # del request.session['username']
        # del request.session['password']
    
        # 退出会话,方式三,推荐方式,django_session表不会产生垃圾数据
        request.session.flush()
    
        return response

    Token自定义服务端会话技术。Cookie依赖于浏览器,Session要利用Cookie的Set-Cookie:sessionid=xxx,所以还是依赖浏览器。对于非BS架构的,如CS架构,就不能使用Cookie和Session会话技术。

    models.py

    class Staff(models.Model):
        name=models.CharField(max_length=16)
        token=models.CharField(max_length=16,null=True)

    views.py

    def login(request):
        name=request.POST.get('name')
        print('name=',name)
        try:
            staff=Staff.objects.get(name=name)
            token=uuid.uuid4().hex
            staff.token=token
            staff.save()
            data={
                'msg':'ok',
                'token':token
            }
            return JsonResponse(data)
        except:
            return JsonResponse({'msg': '用户不存在,或不唯一'})
    
    
    def mine(request):
        token=request.GET.get('token')
        try:
            staff=Staff.objects.get(token=token)
            data={
                'msg':'ok',
                'name':staff.name
            }
            return JsonResponse(data)
        except:
            return JsonResponse({'msg':'用户不存在,或不唯一'})

    settings.py  # 'django.middleware.csrf.CsrfViewMiddleware', 

    类似手机应用服务端接口,所以使用 Postman配合验证。

  • 相关阅读:
    jQuery常用方法一览
    基于jQuery的AJAX和JSON实现纯html数据模板
    jQuery+ASP.NET的AJAX文件上传
    jquery 新建的元素事件绑定问题
    二、visual studio 2008 快捷键
    Sql Server表相关的语句
    使用临时表
    IIS如何启用Gzip压缩功能
    php5.2 的 php.ini 中文版
    joomla笔记——对joomla的初步认识
  • 原文地址:https://www.cnblogs.com/xiongjiawei/p/13751483.html
Copyright © 2011-2022 走看看