Django

Django配置与创建

(1)创建Django项目

django-admin startproject 文件名

(2)启动Django文件

python manage.py runserver

image

(3)创建app

python manage.py startapp 应用名
# python manage.py startapp app01

(4)注册app

  • 创建app后,如果想使用相关的功能,必须将创建的app注册到配置文件中
# 在settings里加入刚才创建的app名
INSTALLED_APPS = [
  'django.contrib.admin',
  'django.contrib.auth',
  'django.contrib.contenttypes',
  'django.contrib.sessions',
  'django.contrib.messages',
  'django.contrib.staticfiles',
   # 找到对应的配置内容中,加入当前新创建的APP的名字
  'app01'
]

Django小白必会三板斧

(1)HttpResponse

  • HttpResponse: 这是 Django 自带的类,用于构建基本的 HTTP 响应。
from django.http import HttpResponse

def index(request):
    return HttpResponse("Hello, world!")

(2)render

  • render 是 Django 框架中的一个函数,通常用于将模板与上下文数据结合渲染成一个完整的 HTTP 响应。它简化了在视图函数中加载模板、填充数据、渲染响应的过程。
from django.shortcuts import render

def index(request):
    # 定义一些数据
    context = {
        'name': 'heart',
        'age': 18,
        'hobby': 'music',
    }
    # 渲染模板并返回 HTTP 响应
    return render(request, 'index.html', context)
<!DOCTYPE html>
<html>
<head>
    <title>index</title>
</head>
<body>
    <h1>Hello, {{ name }}!</h1>
    <p>You are {{ age }} years old and hobby is {{ hobby }}</p>
</body>
</html>

image

(3)redirect

  • 在Django中,redirect是一个函数,用于将请求重定向到另一个URL。
  • 它通常用于在视图函数中处理完成后将用户重定向到其他页面,例如登录后将用户重定向到其个人资料页面。
from django.shortcuts import redirect

def my_view(request):
    # 检查用户是否已登录,如果未登录则重定向到登录页面
    if not User.objects.filter(username=username, password=password)
        return redirect('login')  # 将用户重定向到登录页面
    else:
        # 如果用户已登录,则执行其他操作
        return render(request, 'index.html')

静态文件配置

(1)后端

  • settings.py内配置
# 默认查找位置是当前APP的目录下
# 改变路径需要配置
STATICFILES_DIRS  = [
    os.path.join(BASE_DIR, 'static')
]

(2)前端

  • 在前端页面中增加如下配置,即可使用静态文件模版语法
{% load static %}
<img src="{% static 'img/1.jpg' %}" alt="">

(3)存储引擎mysql配置模板

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': " ",
        "USER": " ",
        "PASSWORD": " ",
        "HOST": "127.0.0.1",
        "PORT": 3306,
        "CHARSET": "utf8mb4",
    }
}

(4)报错注释csrf

  • 在MIDDLEWARE内,注释掉django.middleware.csrf.CsrfViewMiddleware
MIDDLEWARE = [
    # 'django.middleware.csrf.CsrfViewMiddleware',
]

(5)指定MySQL数据库报错

(1)解决办法一:猴子补丁

  • 在项目下的 __init__ 或者任意的应用名下的 __init__ 文件中书写一下代码
import pymysql

pymysql.install_as_MySQLdb()

(2)解决办法二:下载第三方模块

  • 直接安装,看运气报错
pip install mysqlclient

(6)static配置

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static')
]

request对象

(1)GET请求

(1)前端

<form action="" method="get">
  • form表单中action属性,不写默认是当前路由地址
  • form表单中的method属性,不写默认是GET请求
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="" method="get">
    <p>username : <input type="text" name="username"></p>
    <p>password : <input type="password" name="password"></p>
    <p><input type="submit"></p>
</form>
</body>
</html>

(2)后端

  • app01/views.py
from django.shortcuts import render

def register(request):
    return render(request, 'register.html')
  • urls
from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path("register/", views.register)
]

(2)POST请求

(1)前端

<form action="" method="post">
 <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="" method="post">
    <p>username : <input type="text" name="username"></p>
    <p>password : <input type="password" name="password"></p>
    <p><input type="submit"></p>
</form>
</body>
</html>

(2)后端

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

(3)request对象属性和方法

(1)request.method

  • 获取发起请求的请求方式
  • get请求携带的数据是由大小限制的
  • post请求携带的请求参数没有限制
def index(request):
    print(request.method) # GET
    if request.method == 'POST':
        print(request.method) # POST

(2)request.POST

  • 获取用户输入的请求数据,但不包含文件
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="" method="post">
    <p>username : <input type="text" name="username"></p>
    <p>password : <input type="password" name="password"></p>
    <p><input type="submit"></p>
</form>
</body>
</html>

def login(request):
    if request.method == 'POST':
        data = request.POST
        print(data) # <QueryDict: {'username': ['heart'], 'password': ['123']}>
        username = data.get('username')

(3)get/getlist

  • get 只会获取列表最后一个元素
  • getlist 直接将列表取出(多选项)
def index(request):
    if request.method == 'POST':
        data = request.POST
        print(data)  # <QueryDict: {'hobby': ['run', 'music']}>
        hobby_get = data.get('hobby')
        print(hobby_get) # 'music'
        hobby_getlist = data.getlist('hobby')
        print(hobby_getlist)  # ['run', 'music']

路由层

(1)反向解析

  • 反向解析的本质就是先给路由起一个别名,然后通过一些方法去解析别名,可以得到这个别名对应的路由地址
  • 先给路由与视图函数起一个别名

path('index/',views.index,name='index')

urlpatterns = [
    path('admin/', admin.site.urls),
    path('register/', views.register),
	path('index/',views.index,name='index')
]

(2)后端反向解析

from django.shortcuts import render, HttpResponse,reverse
def home(request):
    print(reverse('index'))
    return HttpResponse('test')

(3)前端反向解析

<a href="{% url 'index' %}">111</a>

(4)路由分发

  • 在 Django 中,路由分发是通过 URL 配置和 URL 路由系统来实现的。以下是 Django 中路由分发的基本概念:
  1. URL 配置:在 Django 项目中的 urls.py 文件中配置 URL 路由。这个文件定义了 URL 与视图函数之间的映射关系。
  2. URL 路由:URL 路由系统根据用户请求的 URL 路径将请求分发到相应的视图函数。Django 提供了两种方式来进行 URL 路由:
    • 基于函数的视图(Function-based views):使用 Python 函数作为视图处理函数,通过将 URL 映射到这些函数来处理请求。
    • 基于类的视图(Class-based views):使用基于类的视图来处理请求,这些类提供了一些常用功能的抽象,例如通用视图(Generic views)和视图混合(View mixins)。

(1)主路由urls

  • include

  • path('app01/',include(app01_urls))

from django.contrib import admin
from django.urls import path,include
from app01 import urls as app01_urls

urlpatterns = [
    path('admin/', admin.site.urls),
    path('app01/',include(app01_urls)),
]

(2)子路由urls

  • 需自己手动在项目内创建urls,然后在主路由里添加include,才会生效
from django.urls import path
from app01 import views

urlpatterns = [
    path('register/', views.register),
    path('login/', views.login),
]

image

image

视图层

(1)JsonResponse

  • 原始方法:
import json
from django.shortcuts import HttpResponse

def json_data(request):
    user_dict = {
        "username": "heart你好",
        'age': 18,
        'password': 123,
    }

    # 先转成JSON格式字符串
    # ensure_ascii:中文不编码
    json_str = json.dumps(user_dict, ensure_ascii=False)

    # 然后将该字符串返回
    return HttpResponse(json_str)
  • JsonResponse默认只能序列化字典 序列化其他需要加safe参数
from django.http import JsonResponse
def test(request):
    data = {'name': 'heart你好', 'age': 18}
    return JsonResponse(data)

# {"name": "heart\u4f60\u597d", "age": 18}
# 如果不加 json_dumps_params={'ensure_ascii':False} 会变成二进制

def test(request):
    data = {'name': 'heart你好', 'age': 18}
    return JsonResponse(data, json_dumps_params={'ensure_ascii': False})

# {"name": "heart你好", "age": 18} 加了就正常了
  • 如果要传列表,需要加safe=True
def test(request):
    list = [1,2,3,4,5]
    return JsonResponse(list)

# In order to allow non-dict objects to be serialized set the safe parameter to False.

def test(request):
    list = [1,2,3,4,5]
    return JsonResponse(list,safe=False)

# [1, 2, 3, 4, 5]

(2)form表单上传文件

  • request.FILES

  • file_obj.chunks()

  • 后端代码:

def test(request):
    if request.method == 'POST':
        data = request.POST
        print(data)  # <QueryDict: {'username': ['123']}>

        files = request.FILES
        print(files)  # <MultiValueDict: {'file': [<InMemoryUploadedFile: Django请求生命周期流程图.png (image/png)>]}>

        file_obj = request.FILES.get('file')
        print(file_obj)  # Django请求生命周期流程图.png 拿到的是文件对象

        file_name = file_obj.name
        print(file_name)  # Django请求生命周期流程图.png 拿到的是文件名

        with open(file_name, 'wb') as f:
            for i in file_obj.chunks():  # 推荐加上chunks方法
                f.write(i)

    return render(request, 'files.html')
  • 前端代码:
  • 要上传文件一定要加这个enctype="multipart/form-data"
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div>
    <form action="" method="post" enctype="multipart/form-data">
    <div>username:<input type="text" name ='username'>
         files:<input type="file" name="file">
        <input type="submit" value="提交">
    </div>
    </form>
</div>
</body>
</html>

(3)补充

  • request.path
    • request.path_info
  • request.get_full_path() 能获取完整的url及问号后面的参数
  • eg:
def test1(request):
    print(request.path) # /app01/test1/
    print(request.path_info) # /app01/test1/
    print(request.get_full_path()) # /app01/test1/?name=heart
    return HttpResponse('ok')

image

FBV和CBV

  • 在Django中,FBV(Function-Based Views)和CBV(Class-Based Views)是两种不同的视图编写方式,用于处理HTTP请求并生成HTTP响应。以下是它们的解释:

(1)函数式视图(FBV)

  • 函数式视图是使用Python函数编写的视图。每个函数接收HTTP请求作为输入,并返回HTTP响应。
  • 在函数式视图中,您直接编写处理请求和生成响应的Python函数,这使得它们在一些简单的情况下更为直观和简单。
  • 通过装饰器(如@csrf_exempt@login_required等),您可以很容易地添加各种功能,如CSRF保护、身份验证等。
from django.http import HttpResponse

def my_view(request):
    # 处理请求逻辑
    return HttpResponse("Hello, world!")

(2)类视图(CBV)

  • 类视图是基于类的视图,是一个Python类,其中的方法对应于HTTP请求方法(例如GET、POST等)。

  • 类视图提供了更多的结构化和可重用性,尤其是在处理具有复杂逻辑和共享行为的视图时。

  • Django提供了一系列通用的类视图,如TemplateViewListViewDetailView等,这些类视图已经实现了常见的HTTP请求/响应逻辑,只需通过继承和定制来实现自己的业务逻辑。

  • 后端:

from django.views import View


class MyView(View):
    def get(self, request):
        print(request.method)  # 在刚进入网页的时候,会触发GET请求
        return render(request, 'MyView.html')

    def post(self, request):
        print(request.method)  # 在前端点击提交按钮的时候,会触发POST请求
        return HttpResponse('POST请求')
  • 前端:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="" method="post">
username:<input type="text" name="username">
<input type="submit" name="tijiao"></form>
</body>
</html>

(3)源码剖析

  • urls
urlpatterns = [
    path('MyView/',views.MyView.as_view())
]
# 上述代码在启动django的时候就会立刻执行as_view方法
path('MyView/',views.view) # 和FBV一模一样 CBV与FBV在路由匹配上本质是一样的 都是路由 对应函数内存地址
  • 函数名/方法名 加括号执行优先级最高
  • as_view()
    • 是被@classmethod修饰的类方法
class View:
        http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

    @classonlymethod
    def as_view(cls, **initkwargs):
        # cls是自己写的类
        def view(request, *args, **kwargs): # 闭包函数
            self = cls(**initkwargs)  # cls是我们自己写的类
            # self = MyView(**initkwargs) 产生一个我们自己写的类的对象
            
            self.setup(request, *args, **kwargs) # 更新赋值我们的数据 
            
            # 如果没有request 抛出错误
            if not hasattr(self, 'request'):
                raise AttributeError(
                    "%s instance has no 'request' attribute. Did you override "
                    "setup() and forget to call super()?" % cls.__name__
                )
            #返回 dispatch 函数
            return self.dispatch(request, *args, **kwargs)
        	# 先从对象自己找 再去产生对象的类里面找 之后再去父类里面找
            # 总结:看源码只要看到了self点一个东西 一定要清楚这个self当前是谁
       
        return view

    def setup(self, request, *args, **kwargs):
        if hasattr(self, 'get') and not hasattr(self, 'head'):
            self.head = self.get
        self.request = request
        self.args = args
        self.kwargs = kwargs

    # CBV的精髓
    def dispatch(self, request, *args, **kwargs):
        
        # 获取当前请求的小写格式,然后比对当前请求方法是否合法
        # http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
        if request.method.lower() in self.http_method_names
    		# 反射:通过字符串来操作对象的属性或者方法
        	# handler = getattr(自己写的类产生的对象,请求方法,当找不到请求属性或者方法的时候会用第三个参数)
            # handler = 我们自己写的类里面的请求方法
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        # 如果不存在即抛出异常
        else:
            handler = self.http_method_not_allowed
        # 自动调用请求方法
        return handler(request, *args, **kwargs)

    # 报错
    def http_method_not_allowed(self, request, *args, **kwargs):
        logger.warning(
            'Method Not Allowed (%s): %s', request.method, request.path,
            extra={'status_code': 405, 'request': request}
        )
        return HttpResponseNotAllowed(self._allowed_methods())
  • 当我们启动Django项目时
  • 会自动触发路由中的方法,调用 as_view 方法并自执行
  • 在执行后我们查看 as_view 方法的源码 发现
    • 在依次给我们的对象赋值后,最终返回了一个自执行的 dispatch 方法
  • 于是我们又去查看了 dispatch 方法
    • 在 dispatch 内部 ,先是将请求方式转换并进行校验
    • 然后开始校验需要调用的方法的调用位置,校验成功并拿到需要执行的方法执行
  • 在自己写的类中如果有相关的方法,会首先调用我们重写的类方法,并返回执行结果
    • 如果自己的类里面没有该方法 会去自己的父类中调用 父类的方法
      • 如果父类 以及 基类 都找不到则报错,抛出异常
posted @ 2024-03-11 21:27  ssrheart  阅读(4)  评论(0编辑  收藏  举报