Django配置与创建
(1)创建Django项目
django-admin startproject 文件名
(2)启动Django文件
python manage.py runserver
(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>
(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 中路由分发的基本概念:
- URL 配置:在 Django 项目中的
urls.py
文件中配置 URL 路由。这个文件定义了 URL 与视图函数之间的映射关系。 - 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),
]
视图层
(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')
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提供了一系列通用的类视图,如
TemplateView
、ListView
、DetailView
等,这些类视图已经实现了常见的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 内部 ,先是将请求方式转换并进行校验
- 然后开始校验需要调用的方法的调用位置,校验成功并拿到需要执行的方法执行
- 在自己写的类中如果有相关的方法,会首先调用我们重写的类方法,并返回执行结果
- 如果自己的类里面没有该方法 会去自己的父类中调用 父类的方法
- 如果父类 以及 基类 都找不到则报错,抛出异常
- 如果自己的类里面没有该方法 会去自己的父类中调用 父类的方法