Django实践(1)

Django 框架

创建项目:

1
2
3
4
5
6
7
8
9
10
11
$ django-admin.py startproject test_django
$ cd test_django/
$ tree
.
|-- test_django
| |-- __init__.py
| |-- asgi.py
| |-- settings.py
| |-- urls.py
| `-- wsgi.py
`-- manage.py
  • test_django: 项目的容器。
  • manage.py: 一个实用的命令行工具,以各种方式与该 Django 项目进行交互。
  • test_django/init.py: 一个空文件,告诉 Python 该目录是一个 Python 包。
  • test_django/asgi.py: 一个 ASGI 兼容的 Web 服务器的入口,以便运行项目。
  • test_django/settings.py: 该 Django 项目的设置/配置。
  • test_django/urls.py: 该 Django 项目的 URL 声明; 一份由 Django 驱动的网站”目录”。
  • test_django/wsgi.py: 一个 WSGI 兼容的 Web 服务器的入口,以便运行项目。

CGI(通用网关接口, Common Gateway Interface):定义客户端与Web服务器的交流方式。正常情况下客户端发来一个请求,根据HTTP协议服务器解析请求内容,根据内容操作——例如服务器返回一个HTML页面,并且根据HTTP协议构建返回内容的响应格式。涉及到TCP连接、HTTP原始请求和相应格式的工作,由 CGI 完成。

ASGI(异步网关协议接口):介于网络协议服务和Python应用之间的标准接口,用于解决Python常用的WSGI不支持当前Web开发中的一些新协议标准,是WSGI的扩展。

WSGI(Web服务器网关接口,Python Web Server Gateway Interface):Python为了解决Web服务器端与客户端之间的通信问题而产生的接口——基于Python的以CGI为标准的一些扩展,支持HTTP协议

视图和 URL 配置

新建文件views.py:

1
2
3
4
5
6
7
8
9
$ tree
.
|-- test_django
| |-- __init__.py
| |-- settings.py
| |-- urls.py # url 配置
| |-- views.py # 添加的视图文件
| |-- wsgi.py
`-- manage.py
1
2
3
4
from django.http import HttpResponse

def hello(request):
return HttpResponse("Hello world ! ")

urls.py中配置url;Django path() 函数:

1
path(route, view, kwargs=None, name=None)
  • route: 字符串,表示 URL 规则,与之匹配的 URL 会执行对应的第二个参数 view。
  • view: 用于执行与正则表达式匹配的 URL 请求。(来自views的函数)
  • kwargs: 视图使用的字典类型的参数。
  • name: 用来反向获取 URL。

templates

1
2
3
4
5
6
7
8
9
10
test_django/
|-- test_django
| |-- __init__.py
| |-- settings.py
| |-- urls.py
| |-- views.py
| |-- wsgi.py
|-- manage.py
|-- templates
|-- runoob.html

模板是一个html文本,用于分离文档的表现形式和内容。

修改settings.py,将字典TEMPLATESDIRS键改为 [BASE_DIR, "/templates",]

修改views.py,以向模板提交数据:

1
2
3
4
5
6
from django.shortcuts import render

def runoob(request):
context = {}
context['hello'] = 'Hello World!'
return render(request, 'runoob.html', context)

模板语法:

  • 变量:

    1
    2
    view.py:{"HTML变量名" : "views变量名"
    HTML:{{变量名}}
  • 列表:

    • html中用 . 索引下标取出对应的元素:views_list.0
    • view: return render(request, “runoob.html”, {“views_list”: views_list})
  • 字典:

    • .html中,用 .键 取出对应的值:views_dict.name
    • view:return render(request, “runoob.html”, {“views_dict”: views_dict})
  • filter:

    • .html中:{{ 变量名 | 过滤器:“可选参数” }},过滤器可以在变量被显示前修改它;一个过滤器的输出又可以作为下一个的输入
  • if:

    1
    2
    3
    {% if condition %}
    ... display
    {% endif %}
  • for:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    {% for athlete in athlete_list %}
    <li>{{ athlete.name }}</li>
    {% endfor %}

    {% for athlete in athlete_list reversed %}
    ...
    {% endfor %}

    {% for i,j in views_dict.items %}
    {{ i }}---{{ j }}
    {% endfor %}
    • 内部通过 变量获取循环序号

      • forloop.counter: 顺序获取循环序号,从 1 开始计算
      • forloop.counter0: 顺序获取循环序号,从 0 开始计算
      • forloop.revcounter: 倒叙获取循环序号,结尾序号为 1
      • forloop.revcounter0: 倒叙获取循环序号,结尾序号为 0
      • forloop.first(一般配合if标签使用): 第一条数据返回 True,其他数据返回 False
      • forloop.last(一般配合if标签使用): 最后一条数据返回 True,其他数据返回 False
    • {% empty %} 从句:在循环为空的时候执行

      1
      2
      3
      4
      5
      {% for i in listvar %}
      {{ forloop.counter0 }}
      {% empty %}
      空空如也~
      {% endfor %}
  • ifequal/ifnotequal:

    • 比较两个值,相等时,显示在 {% ifequal %}` 和 `{% endifequal %} 之中所有的值
  • Django 注释使用

  • {% include %}:在模板中包含其它的模板的内容

  • csrf_token:用于form表单中,跨站请求伪造保护

    • {% csrf_token %}标签,在 form 表单提交数据时,才会成功

自定义标签和过滤器

  • 创建 templatetags 目录——只能是此名字——并新建.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    test_django/
    |-- test_django
    | |-- __init__.py
    | |-- __init__.pyc
    | |-- settings.py
    ...
    |-- manage.py
    `-- templatetags
    `-- templates
    | |-- my_tags.py
    1
    2
    3
    from django import template

    register = template.Library() #必须是register
  • settings.py:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    TEMPLATES = [
    {
    ...
    'OPTIONS': {
    'context_processors': [...],
    "libraries":{ # 添加这边三行配置
    'my_tags':'templatetags.my_tags' # 添加这边三行配置
    } # 添加这边三行配置
    },
    },
    ]
  • 装饰器 @register.simple_tag 自定义标签,装饰器 @register.filter 自定义过滤器(参数最多只能2个)

    1
    2
    3
    4
    5
    6
    @register.simple_tag
    def my_tag1(v1, v2, v3):
    return v1 * v2 * v3
    @register.filter
    def my_filter(v1, v2):
    return v1 * v2
  • 使用自定义标签和过滤器前,要在 html 文件 body 的最上方中导入该 py 文件{% load my_tags %}

    1
    2
    {% my_tag1 11 22 33 %}
    {{ 11|my_filter:22 }}
  • 定义标签时,用上 mark_safe 方法,令标签语义化,相当于 jQuery 中的 html() 方法

    1
    2
    3
    4
    5
    from django.utils.safestring import mark_safe
    @register.simple_tag
    def my_html(v1, v2):
    temp_html = "<input type='text' id='%s' class='%s' />" %(v1, v2)
    return mark_safe(temp_html)
    1
    {% my_html "zzz" "xxx" %}

静态文件配置

  • 创建文件夹statics

  • settings.py加入:

    1
    2
    3
    4
    STATIC_URL = '/static/' # 别名 
    STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "statics"),
    ]
  • statics 目录下创建 css 目录,js 目录,images 目录,plugins 目录, 分别放 css文件,js文件,图片,插件

  • bootstrap 框架放入plugins,HTML 文件的 head 标签中引入 bootstrap

    1
    <link rel="stylesheet" href="/static/plugins/bootstrap-3.3.7-dist/css/bootstrap.css">
  • 模板中加入 {% load static %}

    1
    2
    {% load static %}
    {{name}}<img src="{% static "images/runoob-logo.png" %}" alt="runoob-logo">

模板继承

  • 以继承的方式实现复用

  • 父模板(不同的预留区域名字不能相同)

    1
    2
    3
    {% block 名称 %} 
    预留给子模板的区域,可以设置设置默认内容
    {% endblock 名称 %}
  • 子模板(假定base.html为父模板路径)

    1
    2
    3
    4
    {% extends "base.html"%} 
    { % block 名称 % }
    内容
    {% endblock 名称 %}

Model

  • 为数据库提供调用API

  • Django 使用自带的 ORM——Object Relational Mapping,对象关系映射——代码到python对象到ORM到sql语句到数据库,只能操作到数据表的语法,database要自己率先创建image-20201219220911177

  • settings.py 中修改 DATABASES 配置项

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    DATABASES = { 
    'default':
    {
    'ENGINE': 'django.db.backends.mysql', # 数据库引擎
    'NAME': 'runoob', # 数据库名称
    'HOST': '127.0.0.1', # 数据库地址,本机 ip 地址 127.0.0.1
    'PORT': 3306, # 端口
    'USER': 'root', # 数据库用户名
    'PASSWORD': '123456', # 数据库密码
    }
    }
  • 告诉 Django 使用 pymysql 模块连接 mysql 数据库

    1
    2
    3
    # 在与 settings.py 同级目录下的 __init__.py 中引入模块和进行配置
    import pymysql
    pymysql.install_as_MySQLdb()

定义模型

  • Django 规定要使用模型,必须创建一个 app

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    $ django-admin.py startapp TestModel
    $ tree
    .
    test_django
    |-- test_django
    |-- manage.py
    ...
    |-- TestModel
    | |-- __init__.py
    | |-- admin.py
    | |-- models.py
    | |-- tests.py
    | `-- views.py
  • 修改 models.py

    1
    2
    3
    4
    5
    # models.py
    from django.db import models

    class Test(models.Model): # 类名代表了数据库表名,类的字段代表数据表中的字段(name),数据类型为CharField(相当于varchar)、DateField(相当于datetime),max_length 参数限定长度
    name = models.CharField(max_length=20)

    Django 会自动添加一个 id 作为主键。

  • settings.py 的 INSTALLED_APPS 添加 TestModel

  • 运行

    1
    2
    3
    $ python3 manage.py migrate   # 创建表结构
    $ python3 manage.py makemigrations TestModel # 让 Django 知道我们在我们的模型有一些变更
    $ python3 manage.py migrate TestModel # 创建表结构

数据库操作

  • 在 app 目录下新建 testdb.py

  • 在 urls.py 中增加 urlpatterns 元素

    1
    2
    3
    4
    5
    from TestModel import testdb
    urlpatterns = [
    path('runoob/', views.runoob),
    path('testdb/', testdb.testdb),
    ]
  • 添加数据:先创建对象,再 save

    1
    2
    3
    4
    5
    6
    from TestModel.models import Test
    # 数据库操作
    def testdb(request):
    test1 = Test(name='runoob')
    test1.save()
    return HttpResponse("<p>数据添加成功!</p>")
  • 获取数据:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    def testdb(request):
    # 初始化
    response = ""
    response1 = ""
    # 通过objects模型管理器的all()获得所有数据行,即SELECT * FROM
    list = Test.objects.all()
    # filter相当于SQL中的WHERE,可设置条件过滤结果
    response2 = Test.objects.filter(id=1)
    # 获取单个对象
    response3 = Test.objects.get(id=1)
    # 限制返回的数据 相当于 SQL 中的 OFFSET 0 LIMIT 2;
    Test.objects.order_by('name')[0:2]
    #数据排序
    Test.objects.order_by("id")
    # 上面的方法可以连锁使用
    Test.objects.filter(name="runoob").order_by("id")
    # 输出所有数据
    for var in list:
    response1 += var.name + " "
    response = response1
    return HttpResponse("<p>" + response + "</p>")
  • 更新数据:修改数据用 save() 或 update():

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    def testdb(request):
    # 修改其中一个id=1的name字段,再save,相当于SQL中的UPDATE
    test1 = Test.objects.get(id=1)
    test1.name = 'Google'
    test1.save()

    # 另外一种方式
    #Test.objects.filter(id=1).update(name='Google')

    # 修改所有的列
    # Test.objects.all().update(name='Google')

    return HttpResponse("<p>修改成功</p>")
  • 删除数据:调用该对象的delete()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    def testdb(request):
    # 删除id=1的数据
    test1 = Test.objects.get(id=1)
    test1.delete()

    # 另外一种方式
    # Test.objects.filter(id=1).delete()

    # 删除所有数据
    # Test.objects.all().delete()

    return HttpResponse("<p>删除成功</p>")

表单

  • Get:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    # 表单
    def search_form(request):
    return render(request, 'search_form.html')

    # 接收请求数据
    def search(request):
    request.encoding='utf-8'
    if 'q' in request.GET and request.GET['q']:
    message = '你搜索的内容为: ' + request.GET['q']
    else:
    message = '你提交了空表单'
    return HttpResponse(message)
  • Post:POST 方法提交的表格,必须有{% csrf_token %}

    1
    2
    3
    4
    5
    6
    7
    from django.views.decorators import csrf
    # 接收POST请求数据
    def search_post(request):
    ctx ={}
    if request.POST:
    ctx['rlt'] = request.POST['q']
    return render(request, "post.html", ctx)
  • 每个视图函数的第一个参数是 HttpRequest 对象(request 对象)

    • GET和POST属性是django.http.QueryDict类的实例
    • 类似字典的自定义类,处理单键对应多值的情况
      • **get()**:返回字符串,取出该键的最后一个值

视图views

  • views.py
  • request 对象
    • request.path:获取 URL 中的路径部分
    • request.body
    • request.method:获取当前请求的方式(post/get)
  • httpresponse 对象
    • HttpResponse():返回文本,参数为字符串,字符串中写文本内容
    • render():返回文本,第一个参数为 request,第二个参数为字符串(页面名称),第三个参数为字典(可选参数,向页面传递的参数)——render(request,"runoob.html",{"name":name})——一般用于页面跳转
    • redirect():重定向,跳转新页面;一般用于 form 表单提交后,跳转到新页面——redirect("/index/")

路由

  • urls.py

  • 根据用户请求的 URL 链接来判断对应的处理程序,返回处理结果——URL 与 Django 的视图建立映射关系

  • 普通路径:path();正则路径:re_path()

  • 路由分发:

    • Django 项目里多个app目录共用一个 urls 容易造成混淆——使用路由分发(include),让每个app目录都单独拥有自己的 urls

    • 每个 app 目录里都创建一个 urls.py 文件

    • 项目名称目录下的 urls 文件里,统一将路径分发给各个 app 目录

      1
      2
      3
      4
      5
      urlpatterns = [
      path('admin/', admin.site.urls),
      path("app01/", include("app01.urls")),
      path("app02/", include("app02.urls")),
      ]
  • 反向解析

  • 命名空间

Admin管理

  • 自动管理工具已在 INSTALLED_APPS 、urls.py 配置好

  • 通过命令python manage.py createsuperuser来创建超级用户

  • admin 界面管理某个数据模型

    • admin.py:Test为Model类

      1
      2
      3
      # Register your models here.
      admin.site.register(Test)
      # admin.site.register([Test, Contact, Tag])

      image-20201220145346997

    • 修改某一个界面:在表Contact的添加里限定添加的字段、搜索

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      # Register your models here.
      class ContactAdmin(admin.ModelAdmin):
      list_display = ('name','age', 'email') # list
      search_fields = ('name',) # 搜索框
      inlines = [TagInline] # Inline 让表 Tag 附加在 Contact 的编辑页面上显示
      fieldsets = (
      ['Main',{
      'fields':('name','email'),
      }],
      ['Advance',{
      'classes': ('collapse',), # classes 说明它所在的部分的 CSS 格式
      'fields': ('age',),
      }] # 将输入栏分块

      )

      admin.site.register(Contact, ContactAdmin)

image-20201220150840160

表的实例

单个表

  • models.py

    1
    2
    3
    4
    5
    6
    class Book(models.Model):
    id = models.AutoField(primary_key=True) # id 会自动创建,可以手动写入
    title = models.CharField(max_length=32) # 书籍名称
    price = models.DecimalField(max_digits=5, decimal_places=2) # 书籍价格
    publish = models.CharField(max_length=32) # 出版社名称
    pub_date = models.DateField() # 出版时间
  • views.py:

    • books = models.Book.objects.filter(pk=5),pk为primary key

    • exclude() :用于查询不符合条件的数据

    • get() :符合条件的对象只能为一个,如果符合筛选条件的对象超过了一个或者没有都会报错

    • order_by() :对查询结果进行排序

      1
      2
      books = models.Book.objects.order_by("price") # 查询所有,按照价格升序排列 
      books = models.Book.objects.order_by("-price") # 查询所有,按照价格降序排列
    • count() :查询数据的数量

    • first() :返回第一条数据

    • **last()**:返回最后一条数据

    • exists() :判断的数据类型只能为 QuerySet 类型数据,返回 true 和 false

    • values() :用于查询部分字段的数据,返回一个可迭代的字典序列,字典里的键是字段,值是数据

      1
      2
      3
      4
      5
      def add_book(request):
      # 查询所有的id字段和price字段的数据
      books = models.Book.objects.values("pk","price")
      print(books[0]["price"],type(books)) # 得到的是第一条记录的price字段的数据
      return HttpResponse("<p>查找成功!</p>")
    • **values_list()**:返回元组,只有数据

    • **distinct()**:对数据去重

    • filter() :基于双下划线的模糊查询(exclude 同理)。filter 中运算符号只能使用=

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      def add_book(request):
      # 查询价格为200或者300的数据
      books = models.Book.objects.filter(price__in=[200,300])
      # 查询价格大于200的数据
      books = models.Book.objects.filter(price__gt=200)
      # 查询价格大于等于200的数据
      books = models.Book.objects.filter(price__gte=200)
      # 查询价格小于300的数据
      books = models.Book.objects.filter(price__lt=300)
      # 查询价格小于等于300的数据
      books = models.Book.objects.filter(price__lte=300)
      # 在。。。之间,左闭右闭
      books = models.Book.objects.filter(price__range=[200,300])
      # 包含
      books = models.Book.objects.filter(title__contains="菜")
      # 不区分大小写的包含
      books = models.Book.objects.filter(title__icontains="python")
      # 以指定字符开头
      books = models.Book.objects.filter(title__startswith="菜")
      books = models.Book.objects.filter(title__endswith="教程")
      # DateField 数据类型的年份、月份、天
      books = models.Book.objects.filter(pub_date__year=2008)
      books = models.Book.objects.filter(pub_date__month=10)
      books = models.Book.objects.filter(pub_date__day=1)
      return HttpResponse("<p>查找成功!</p>")
    • QuerySet 类型数据.update(字段名=更改的数据),返回值:整数,受影响的行数 / 模型类的对象.属性 = 更改的属性值,模型类的对象.save()

多个表

  • models.py:模型类存在外键,创建数据时,要先创建外键关联的模型类的数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    pub_date = models.DateField()
    publish = models.ForeignKey("Publish", on_delete=models.CASCADE) # 外键在一对多的多中设置
    authors = models.ManyToManyField("Author")


    class Publish(models.Model):
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=64)
    email = models.EmailField() # EmailField 数据类型是邮箱格式, 继承 CharField


    class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.SmallIntegerField()
    au_detail = models.OneToOneField("AuthorDetail", on_delete=models.CASCADE) # OneToOneField = ForeignKey(...,unique=True)设置一对一


    class AuthorDetail(models.Model):
    gender_choices = (
    (0, "女"),
    (1, "男"),
    (2, "保密"),
    )
    gender = models.SmallIntegerField(choices=gender_choices)
    tel = models.CharField(max_length=32)
    addr = models.CharField(max_length=64)
    birthday = models.DateField()
  • 添加数据

    • 一对多

      1
      2
      3
      4
      5
      6
      7
      8
      9
      def add_book(request):
      # 获取出版社对象
      pub_obj = models.Publish.objects.filter(pk=1).first()
      # 获取出版社对象的id
      pk = pub_obj.pk
      # 给书籍的关联出版社字段 publish_id 传出版社对象的id
      book = models.Book.objects.create(title="冲灵剑法", price=100, pub_date="2004-04-04", publish_id=pk)
      print(book, type(book))
      return HttpResponse(book)
    • 多对多

      1
      2
      3
      4
      5
      6
      7
      8
      9
      def add_book(request):
      # 获取作者对象
      chong = models.Author.objects.filter(name="令狐冲").first()
      # 获取作者对象的id
      pk = chong.pk
      # 获取书籍对象
      book = models.Book.objects.filter(title="冲灵剑法").first()
      # 给书籍对象的 authors 属性用 add 方法传作者对象的id
      book.authors.add(pk)
  • 查询

    • 基于对象的跨表查询

      • 正向:属性名称 反向:小写类名_set

        1
        2
        3
        4
        # 查询主键为 1 的书籍的出版社所在的城市(正向)
        res = models.Book.objects.filter(pk=10).first().publish.city
        # 查询明教出版社出版的书籍名(反向)
        pub = models.Publish.objects.filter(name="明教出版社").first().book_set.all()
    • 基于双下划线的跨表查询

      • 正向:属性名称__ 跨表的属性名称 反向:小写类名__跨表的属性名称

        1
        2
        3
        4
        5
        6
        # 查询菜鸟出版社出版过的所有书籍的名字与价格
        res = models.Book.objects.filter(publish__name="菜鸟出版社").values_list("title", "price")
        res = models.Publish.objects.filter(name="菜鸟出版社").values_list("book__title","book__price")
        # 查询任我行出过的所有书籍的名字
        res = models.Book.objects.filter(authors__name="任我行").values_list("title")
        res = models.Author.objects.filter(name="任我行").values_list("book__title")

用户认证(Auth)组件

  • 一般用在用户的登录注册上,用于判断当前的用户是否合法,并跳转到登陆成功或失败页面

  • 模块:

    1
    2
    3
    4
    5
    # 认证模块
    from django.contrib import auth

    # 对应数据库
    from django.contrib.auth.models import User
  • 用户创建:

    1
    2
    3
    4
    from django.contrib.auth.models import User 
    User.objects.create(username='runboo',password='123') # 创建一个普通用户,密码是明文的
    User.objects.create_user(username='runbooo',password='123') # 创建一个普通用户,密码是密文的
    User.objects.create_superuser(username='runboooo',password='123',email='runboo@163.com') # 创建一个超级用户,密码是密文的,要多传一个邮箱 email 参数
  • views.py.login()

    • 验证用户的用户名和密码使用 authenticate()

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      def login(request):
      if request.method == "GET":
      return render(request, "login.html")
      username = request.POST.get("username")
      password = request.POST.get("pwd")
      valid_num = request.POST.get("valid_num")
      keep_str = request.session.get("keep_str")
      if keep_str.upper() == valid_num.upper():
      user_obj = auth.authenticate(username=username, password=password)
      print(user_obj.username)
      if not user_obj:
      return redirect("/login/")
      else:
      auth.login(request, user_obj)
      path = request.GET.get("next") or "/index/"
      print(path)
      return redirect(path)
      else:
      return redirect("/login/")
    • 验证成功返回用户对象,反之,返回 None

  • views.py.logout()

    • 注销用户,清空 session 信息,将 request.user 赋值为匿名用户

      1
      2
      3
      4
      def logout(request):
      ppp = auth.logout(request)
      print(ppp) # None
      return redirect("/login/")
  • 给需要登录成功后才能访问的页面统一加装饰器

    1
    2
    3
    4
    from django.contrib.auth.decorators import login_required 
    @login_required
    def index(request):
    return HttpResponse("index页面。。。")
  • 返回登录前的页面

    1
    2
    3
    # 如果直接输入 login、get() 就取不到值,path 可以自定义设置返回的页面
    path = request.GET.get("next") or "/index/"
    return redirect(path)

参考

菜鸟教程 Django