Django 基础 2 -- 路由相关

548 阅读7分钟

web 服务器

web服务器也叫”http web 服务器“,专门用于提供网页浏览器的一类软件。 常见的web 服务器软件:nginx,uwsgi,gunicorn,apache,tomcat,iis 等 wsgi:Python 基于 CGI 标准实现的 HTTP 通讯技术 asgi:async+wsgi,支持异步的 wsgi软件

路由

路由是把客户端请求的url地址和用户请求的应用程序[这里意指django里面的视图]进行一对一绑定映射的一种关系.

视图

视图函数FBV

function baseview 视图函数必须编写扎起子应用的 views.py 文件中

from django.http.response import HttpResponse
def 函数视图名称(request):
    # 代码
    return HttpResponse("返回内容")

视图函数的名称,同一模块下不能重复,命名规则同变量命名规则

视图类

class baseview

请求

限制 HTTP 请求

web项目运行在http协议下,默认肯定也支持用户通过不同的http请求发送数据来。 常见的 HTTP 请求

POST: 添加/上传
GET : 获取/下载
PUT/PATCH : 修改,其中PUT表示修改整体数据,而PATCH表示修改部分数据
DELETE:删除,废弃

Django 支持让客户端只能通过指定的 HTTP 请求来访问到项目用的视图

home/views.py,代码:

# 让用户发送POST才能访问的页面
from django.views.decorators.http import require_http_methods
@require_http_methods(["POST"])
def login(request):
    return HttpResponse("登录成功!")

路由绑定

demo/urls.py,代码:

from django.contrib import admin
from django.urls import path
from home.views import index,index2
urlpatterns = [
    path('admin/', admin.site.urls),
    path("index", index),
    path("login", login),
]

浏览器中由于默认用 get 方法访问,而我们设置的只支持 post 方法所以会报错。 正常情况下,我们用户发送POST一般肯定通过使用html网页中的表单/js里面提供http请求的ajax才可以做到发送POST或GET或PUT/PATCH,而现在我们没有表单,因此我们可以安装一个postman的软件,这个软件类似浏览器但是功能比浏览器要强大,专门提供给开发人员免费使用的。

采用 postman 方式进行访问,但由于一种安全访问机制,我们需要将 demo/settings.py 文件进行设置

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',   # ctrl+/
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

设置路由绑定视图

为了有效管理路由设置,我们可以将路由放回到子应用目录下

  1. 在子应用 home 下创建路由文件夹,一般命名为urls.py
  2. 将子应用home 下的视图绑定到该文件下
"""子应用路由"""
from django.urls import path
# 路由使用过程中,django提供了2个函数给我们把url和视图进行绑定映射,
# django.urls.path
# django.urls.re_path
from . import views
urlpatterns = [
    path('home', views.index),
    path('list', views.book_list),
    # path("路由uri地址", 视图代码)
    path('login', views.login),
]

# 最终用户访问的视图url地址:
# url = 总路由的公共url地址 + 子应用路由的uri地址
  1. 在总路由中 demo/urls.py 问津中,通过 include 加载路由文件到 Django 项目中 demo/urls.py
"""总路由"""
from django.contrib import admin
from django.urls import path,include
urlpatterns = [
    path('admin/', admin.site.urls),
    # path("公共url地址", include("子应用目录名.路由模块"))
    path("book/", include("home.urls")),
]

当django项目中的路由分成总路由和子应用路由以后, 那么用户访问视图,则访问地址的规则:

http://127.0.0.1:8000/路由前缀+子应用路由的url地址

例如: 总路由中注册子应用路由时, 路由前缀为 "home" 则用户访问时 正确的地址就是: http://127.0.0.1:8000/homeindex

当然,如果路由前缀是 "home/", 而子路由的url地址为 "index"
则用户访问时 正确的地址就是: http://127.0.0.1:8000/home/index

视图接收 HTTP 请求

在http请求和响应过程中, 用户往往会在请求过程中发送请求信息给服务端.

  1. 查询字符串[Query String] 所谓的查询字符串就是url地址上面?号后面的数据,例如: http://127.0.0.1:8000/index?name=xiaoming&pwd=123456 上面name=xiaoming&pwd=123456就是查询字符串 可以通过 request.GET 来获取,注意: GET不是http请求,也就是说,只要地址上有查询字符串,都可以获取

  2. 请求体数据

  3. 请求头报文信息

  4. 上传文件

获取查询字符串的参数

home/views.py

"""查询字符串[Query String]"""
def index3(request):
    # print(request.method)
    """
    访问地址: 
        http://127.0.0.1:8000/home/index3
    打印效果:
        <QueryDict: {}>
        
    分析: 通过request得到的客户端请求数据,基本都是会保存成QueryDict类字典给视图的,上面是空字典
          QueryDict的声明位置: from django.http import QueryDict
          QueryDict的父类继承的就是dict字典,所以字典提供的方法或者操作, QueryDict都有
    """
    """
    访问地址:
         http://127.0.0.1:8000/home/index3?name=xiapming&mobile=13312345678
    打印效果:
         <QueryDict: {'name': ['xiapming'], 'mobile': ['13312345678']}>
    分析:
        这次就获取到了name和mobile参数以及参数的值
        注意:
            因为客户端传递过来的参数有可能多个值的情况,所以查询字符串返回的数据值都是列表格式
    """
    """
    访问地址:
         http://127.0.0.1:8000/home/index3?name=xiapming&mobile=13312345678&lve=swimming&lve=shopping&lve=game
    打印效果:
        <QueryDict: {'name': ['xiapming'], 'mobile': ['13312345678'], 'lve': ['swimming', 'shopping', 'game']}>
    分析:
        因为lve有多个值的存在, 所以值就是列表中有3个成员
    """

    """获取QueryDict对象中的参数值"""
    # 获取参数的一个值,或者第一个值
    # 因为QueryDict是一个伪字典对象,所以可以通过get或者中括号获取到数据
    # print(request.GET.get("name"))
    # print(request.GET["name"])

    # 获取参数的所有值
    print(request.GET.getlist("lve")) # ['swimming', 'shopping', 'game']
    print(request.GET['lve']) # game,后面的值覆盖了前面的值

    return HttpResponse("ok")

home/urls.py:

from django.urls import path

from . import views
urlpatterns = [
    path("index", views.index ),
    path("index2", views.index2 ),
    path("index3", views.index3 ),
]

获取请求体数据

def index4(request):
    """获取请求体数据,返回数据结果是QueryDict"""
    print(request.POST)
    """
    打印效果:
    <QueryDict: {'name': ['root'], 'password': ['123456']}>
    
    """

    print(request.body) #  b'{\n\t"title": "\xe5\x9c\xa3\xe8\xaf\x9e\xe6\xa0\x91",\n    "username":"\xe5\x9c\xa3\xe8\xaf\x9e\xe8\x80\x81\xe5\xa4\xb4",\n    "age": 1200\n}'
    """
    打印效果:
    b'{\n\t"title": "\xe5\x9c\xa3\xe8\xaf\x9e\xe6\xa0\x91",\n    "username":"\xe5\x9c\xa3\xe8\xaf\x9e\xe8\x80\x81\xe5\xa4\xb4",\n    "age": 1200\n}'
    """
    import json
    ret = json.loads(request.body)
    print(ret) # {'title': '圣诞树', 'username': '圣诞老头', 'age': 1200}

    return HttpResponse("ok")

home/urls.py代码:

from django.urls import path

from . import views
urlpatterns = [
    path("index", views.index ),
    path("index2", views.index2 ),
    path("index3", views.index3 ),
    path("index4", views.index4 ),
]

获取请求头数据

def index4(request):

    
    """获取请求头信息"""
    print( request.META.get("CONTENT_TYPE") ) # application/json
    """获取自定义请求头"""
    print( request.META.get("HTTP_COMPANY")) # oldboyedu

    return HttpResponse("ok")

获取上传文件

    print(request.FILES) # <MultiValueDict: {'avatar': [<InMemoryUploadedFile: 老男孩教育-数据库-存储迁移.jpg (image/jpeg)>]}>
    print(request.FILES.get("avatar")) # 老男孩教育-数据库-存储迁移.jpg
    print(type( request.FILES.get("avatar")) ) # <class 'django.core.files.uploadedfile.InMemoryUploadedFile'>

响应

视图相应数据

  1. 响应内容

    直接返回数据给客户端包括 HTML 内容(一般用于前后端不分离项目)和json 内容(前后端分离的 API 接口开发)

  2. 响应页面

    通过返回页面跳转的信息给浏览器,让浏览器自己进行页面跳转

返回 HTML 数据

ef index5(request):
    """响应对象"""
    """
    return HttpResponse(content="正文内容",content_type="内容格式",status="http响应状态码")
    content_type 内容格式,默认是 text/html
    status       响应状态码,默认是 200
    """

    """返回html内容"""
    return HttpResponse("<h1>hello world</h1>")

返回 JSON 数据

from django.http.response import JsonResponse
import json
def index5(request):
    """响应对象"""
    """返回json数据"""
    # data = {
    #     "id":1,
    #     "username":"张晓明",
    #     "money": 22.50,
    #     "sex":True,
    #     "lve":["swimming","walk","game"]
    # }
    # goods_list = [
    #     {"id":1,"num":10,"name":"产品1"},
    #     {"id":2,"num":10,"name":"产品2"},
    #     {"id":3,"num":10,"name":"产品3"},
    #     {"id":4,"num":10,"name":"产品4"},
    # ]
    # # 方式1,如果返回非字典数据,务必设置 sale=False 才行.
    # # return HttpResponse(json.dumps(data), content_type="application/json")
    # # 方式2,如果返回非字典数据,务必设置 sale=False 才行.
    # return JsonResponse(goods_list,safe=False)

返回图片信息

def index5(request):
    """响应对象"""

    """通过响应对象不仅可以返回HTML网页信息,还可以返回纯文本,或者图片,甚至完成文件下载的功能[这个过程只需要设置content_type即可]"""
    # content = open("release.png","rb").read()
    # return HttpResponse(content,content_type="image/jpeg")

提供下载支持

def index5(request):
    """响应对象"""
    """还可以是其他格式数据,用于提供下载"""
    # with open("./basic-2.2.1.zip","rb") as f:
    #     content = f.read()
    # return HttpResponse(content,content_type="application/x-zip-compressed")

自定义响应头

def index5(request):
    """响应对象"""

    """返回数据的过程中设置响应头"""
    response = HttpResponse("ok")

    # 自定义响应头[值和属性都不能是多字节]
    response["company"] = "oldboyedu"
    return response

页面跳转

# 跳转到站外
def index5(request):
    """响应对象"""
	from django.shortcuts import redirect
    # 方式1
    # return HttpResponseRedirect("http://www.baidu.com")

    # 方式2
    # return redirect("http://www.baidu.com")
   
# 跳转到站内
def center(request):
    # 方式1
    # return redirect("/student/login")

    # 方式2
    print( reverse("stu:user_login") ) # 路由反转,自动根据编写的视图方式名反解析成url地址
    return redirect( reverse("stu:user_login") )

def login(request):
    return HttpResponse("登录页面")

在站内跳转时,如果使用reverse进行路由反转解析,则必须在总路由和子路由文件中,对路由的前缀和子路由进行别名绑定.方法如下:

# 总路由
from django.contrib import admin
from django.urls import path
from django.urls import include

urlpatterns = [
    path('admin/', admin.site.urls),
    # path('home/', include('home.urls',namespace="应用别名") ),
    path('student/', include('demo.student.urls',namespace="stu") ),
]


# 子路由文件,例如:student/urls.py
from django.urls import path
from . import views
app_name = "student" # 当前子应用的包名
urlpatterns = [
    # path("index", views.index ),
    # path("index2", views.index2 ),
    # path("index3", views.index3 ),
    path("center", views.center ),
    path("login", views.login, name="user_login" ),
]