Django视图和URL
一、课程概述
学习项目 | 具体内容 | 预计用时 |
---|---|---|
视图基础 | 函数视图、类视图、视图装饰器 | 90分钟 |
URL配置 | URL模式、路由系统、命名URL | 60分钟 |
请求处理 | 请求对象、响应对象、中间件 | 90分钟 |
二、视图基础
2.1 函数视图
# blog/views.py
from django.shortcuts import render, get_object_or_404, redirect
from django.http import HttpResponse
from .models import Post, Category
from .forms import PostForm
# 简单的函数视图
def hello_world(request):
return HttpResponse("Hello, Django!")
# 带模板渲染的视图
def post_list(request):
posts = Post.objects.all().order_by('-publish')
return render(request, 'blog/post_list.html', {'posts': posts})
# 处理表单的视图
def post_create(request):
if request.method == 'POST':
form = PostForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
post.author = request.user
post.save()
return redirect('blog:post_detail', post.id)
else:
form = PostForm()
return render(request, 'blog/post_form.html', {'form': form})
# 详情视图
def post_detail(request, post_id):
post = get_object_or_404(Post, id=post_id)
return render(request, 'blog/post_detail.html', {'post': post})
2.2 类视图
# blog/views.py
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from django.urls import reverse_lazy
from django.contrib.auth.mixins import LoginRequiredMixin
# 列表视图
class PostListView(ListView):
model = Post
template_name = 'blog/post_list.html'
context_object_name = 'posts'
paginate_by = 10
ordering = ['-publish']
def get_queryset(self):
queryset = super().get_queryset()
category_id = self.request.GET.get('category')
if category_id:
queryset = queryset.filter(category_id=category_id)
return queryset
# 详情视图
class PostDetailView(DetailView):
model = Post
template_name = 'blog/post_detail.html'
context_object_name = 'post'
# 创建视图
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
template_name = 'blog/post_form.html'
fields = ['title', 'body', 'category', 'status']
success_url = reverse_lazy('blog:post_list')
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
# 更新视图
class PostUpdateView(LoginRequiredMixin, UpdateView):
model = Post
template_name = 'blog/post_form.html'
fields = ['title', 'body', 'category', 'status']
def get_success_url(self):
return reverse_lazy('blog:post_detail', kwargs={'pk': self.object.pk})
# 删除视图
class PostDeleteView(LoginRequiredMixin, DeleteView):
model = Post
success_url = reverse_lazy('blog:post_list')
template_name = 'blog/post_confirm_delete.html'
2.3 视图装饰器
# blog/views.py
from django.contrib.auth.decorators import login_required, permission_required
from django.views.decorators.http import require_http_methods
from django.views.decorators.cache import cache_page
# 登录要求装饰器
@login_required
def profile(request):
return render(request, 'blog/profile.html', {'user': request.user})
# HTTP方法限制装饰器
@require_http_methods(["GET", "POST"])
def post_edit(request, post_id):
post = get_object_or_404(Post, id=post_id)
if request.method == 'POST':
# 处理POST请求
pass
return render(request, 'blog/post_edit.html', {'post': post})
# 缓存装饰器
@cache_page(60 * 15) # 缓存15分钟
def category_list(request):
categories = Category.objects.all()
return render(request, 'blog/category_list.html', {'categories': categories})
三、URL配置
3.1 URL模式
# blog/urls.py
from django.urls import path
from . import views
app_name = 'blog'
urlpatterns = [
# 函数视图URL
path('', views.post_list, name='post_list'),
path('post/<int:post_id>/', views.post_detail, name='post_detail'),
path('post/new/', views.post_create, name='post_create'),
# 类视图URL
path('posts/', views.PostListView.as_view(), name='posts'),
path('post/<int:pk>/detail/', views.PostDetailView.as_view(), name='post_detail'),
path('post/add/', views.PostCreateView.as_view(), name='post_add'),
path('post/<int:pk>/edit/', views.PostUpdateView.as_view(), name='post_edit'),
path('post/<int:pk>/delete/', views.PostDeleteView.as_view(), name='post_delete'),
# 带参数的URL
path('category/<slug:category_slug>/', views.category_posts, name='category_posts'),
path('tag/<slug:tag_slug>/', views.tag_posts, name='tag_posts'),
path('archive/<int:year>/<int:month>/', views.archive_posts, name='archive_posts'),
]
3.2 高级URL配置
# myproject/urls.py
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path('blog/', include('blog.urls', namespace='blog')),
path('api/', include('blog.api.urls')), # API URLs
path('accounts/', include('django.contrib.auth.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
# 自定义错误页面
handler404 = 'myproject.views.custom_404'
handler500 = 'myproject.views.custom_500'
四、请求和响应处理
4.1 请求对象
# blog/views.py
def process_request(request):
# 获取GET参数
page = request.GET.get('page', 1)
category = request.GET.get('category')
# 获取POST数据
if request.method == 'POST':
title = request.POST.get('title')
content = request.POST.get('content')
# 获取文件
if request.FILES:
image = request.FILES['image']
# 获取cookies
user_id = request.COOKIES.get('user_id')
# 获取session数据
cart = request.session.get('cart', {})
# 获取用户信息
if request.user.is_authenticated:
username = request.user.username
4.2 响应对象
# blog/views.py
from django.http import JsonResponse, FileResponse, StreamingHttpResponse
from django.shortcuts import render, redirect
def multiple_responses(request):
# HTML响应
return render(request, 'template.html', context)
# 重定向
return redirect('blog:post_list')
# JSON响应
data = {'status': 'success', 'message': 'Data received'}
return JsonResponse(data)
# 文件下载
file_path = 'path/to/file.pdf'
return FileResponse(open(file_path, 'rb'))
# 流式响应
def file_iterator(file_path, chunk_size=8192):
with open(file_path, 'rb') as f:
while True:
chunk = f.read(chunk_size)
if not chunk:
break
yield chunk
return StreamingHttpResponse(file_iterator(file_path))
4.3 中间件
# blog/middleware.py
import time
from django.utils.deprecation import MiddlewareMixin
class RequestTimingMiddleware(MiddlewareMixin):
def process_request(self, request):
request.start_time = time.time()
def process_response(self, request, response):
if hasattr(request, 'start_time'):
duration = time.time() - request.start_time
response['X-Request-Duration'] = str(duration)
return response
# settings.py
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'blog.middleware.RequestTimingMiddleware', # 自定义中间件
]
五、实战示例:博客搜索功能
# blog/views.py
from django.db.models import Q
def post_search(request):
query = request.GET.get('q', '')
results = []
if query:
results = Post.objects.filter(
Q(title__icontains=query) |
Q(body__icontains=query) |
Q(tags__name__icontains=query)
).distinct()
return render(request,
'blog/search.html',
{'query': query,
'results': results})
# blog/templates/blog/search.html
{% extends "blog/base.html" %}
{% block content %}
<h2>搜索结果</h2>
<form method="get">
<input type="text" name="q" value="{{ query }}" placeholder="搜索文章...">
<button type="submit">搜索</button>
</form>
{% if query %}
<h3>包含 "{{ query }}" 的文章:</h3>
{% if results %}
{% for post in results %}
<article>
<h4><a href="{% url 'blog:post_detail' post.id %}">{{ post.title }}</a></h4>
<p>{{ post.body|truncatewords:30 }}</p>
</article>
{% endfor %}
{% else %}
<p>没有找到相关文章。</p>
{% endif %}
{% endif %}
{% endblock %}
六、常见问题和解决方案
- 处理404错误:
# views.py
from django.http import Http404
def post_detail(request, post_id):
try:
post = Post.objects.get(id=post_id)
except Post.DoesNotExist:
raise Http404("Post does not exist")
return render(request, 'blog/post_detail.html', {'post': post})
- CSRF验证:
<!-- templates/form.html -->
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">提交</button>
</form>
- 文件上传处理:
# views.py
def upload_file(request):
if request.method == 'POST' and request.FILES['file']:
myfile = request.FILES['file']
fs = FileSystemStorage()
filename = fs.save(myfile.name, myfile)
uploaded_file_url = fs.url(filename)
return render(request, 'upload.html', {
'uploaded_file_url': uploaded_file_url
})
return render(request, 'upload.html')
七、作业和练习
- 实现一个完整的CRUD操作系统
- 创建自定义的中间件
- 实现文件上传和下载功能
- 编写RESTful风格的URL设计
- 实现用户认证和授权系统
八、扩展阅读
- Django CBV (Class-Based Views) 详解
- Django中间件开发最佳实践
- RESTful API设计原则
- Django安全最佳实践
怎么样今天的内容还满意吗?再次感谢朋友们的观看,关注GZH:凡人的AI工具箱,回复666,送您价值199的AI大礼包。最后,祝您早日实现财务自由,还请给个赞,谢谢!