每天40分玩转Django:Django视图和URL

news2024/12/14 16:33:50

Django视图和URL

一、课程概述

学习项目具体内容预计用时
视图基础函数视图、类视图、视图装饰器90分钟
URL配置URL模式、路由系统、命名URL60分钟
请求处理请求对象、响应对象、中间件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 %}

六、常见问题和解决方案

  1. 处理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})
  1. CSRF验证:
<!-- templates/form.html -->
<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">提交</button>
</form>
  1. 文件上传处理:
# 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')

七、作业和练习

  1. 实现一个完整的CRUD操作系统
  2. 创建自定义的中间件
  3. 实现文件上传和下载功能
  4. 编写RESTful风格的URL设计
  5. 实现用户认证和授权系统

八、扩展阅读

  1. Django CBV (Class-Based Views) 详解
  2. Django中间件开发最佳实践
  3. RESTful API设计原则
  4. Django安全最佳实践

怎么样今天的内容还满意吗?再次感谢朋友们的观看,关注GZH:凡人的AI工具箱,回复666,送您价值199的AI大礼包。最后,祝您早日实现财务自由,还请给个赞,谢谢!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2259432.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

token失效重新存储发起请求

import axios from axios import { MessageBox, Message } from element-ui import store from /store import Router from /router import { getCookie, setToken, setCookie } from ./auth// 因为后端环境区分v1 v2 剔除测试盛传的环境配置&#xff0c;并添加统一前缀 const …

悬赏任务源码(悬赏发布web+APP+小程序)开发附源码

悬赏任务源码是指一个软件或网站的源代码&#xff0c;用于实现悬赏任务的功能。悬赏任务是指发布方提供一定的奖励&#xff0c;希望能够找到解决特定问题或完成特定任务的人。悬赏任务源码通常包括任务发布、任务接受、任务完成和奖励发放等功能的实现。搭建悬赏任务源码是一个…

【一本通】虫洞

【一本通】虫洞 C语言代码C代码JAVA代码 &#x1f490;The Begin&#x1f490;点点关注&#xff0c;收藏不迷路&#x1f490; John在他的农场中闲逛时发现了许多虫洞。虫洞可以看作一条十分奇特的有向边&#xff0c;并可以使你返回到过去的一个时刻&#xff08;相对你进入虫洞之…

Linux之条件变量,信号量,生产者消费者模型

Linux之条件变量&#xff0c;信号量&#xff0c;生产消费者模型&#xff0c;日志以及线程池 一.条件变量1.1条件变量的概念1.2条件变量的接口 二.信号量2.1信号量的重新认识2.2信号量的接口 三.生产者消费者模型3.1生产者消费者模型的概念3.2基于阻塞队列的生产者消费者模型3.3…

如何写出优秀的单元测试?

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 写出优秀的单元测试需要考虑以下几个方面&#xff1a; 1. 测试用例设计 测试用例应该覆盖被测试代码的不同场景和边界情况&#xff0c;以尽可能发现潜在的问题。…

【竞技宝】LOL:JDG官宣yagao离队

北京时间2024年12月13日,在英雄联盟S14全球总决赛结束之后,各大赛区都已经进入了休赛期,目前休赛期也快进入尾声,LPL大部分队伍都开始陆续官宣转会期的动向,其中JDG就在近期正式官宣中单选手yagao离队,而后者大概率将直接选择退役。 近日,JDG战队在官方微博上连续发布阵容变动消…

2024美赛数学建模C题:网球比赛中的动量,用马尔可夫链求解!详细分析

文末获取历年美赛数学建模论文&#xff0c;交流思路模型 接下来讲解马尔可夫链在2024年C题中的运用 1. 马尔科夫链的基本原理 马尔科夫链是描述随机过程的一种数学模型&#xff0c;其核心特征是无记忆性。 简单来说&#xff0c;系统在某一时刻的状态只取决于当前状态&#x…

图形学笔记 - 5. 光线追踪 - RayTracing

Whitted-Style Ray tracing 为什么要光线追踪 光栅化不能很好地处理全局效果 软阴影尤其是当光线反射不止一次的时候 栅格化速度很快&#xff0c;但质量相对较低 光线追踪是准确的&#xff0c;但速度很慢 光栅化&#xff1a;实时&#xff0c;光线追踪&#xff1a;离线~10K …

Nginx之配置防盗链(Configuring Anti-hotlinking in Nginx)

运维小白入门——Nginx配置防盗 什么是防盗链&#xff1a; 防盗链技术主要用于防止未经授权的第三方或域名访问网站的静态资源。例如&#xff0c;一个网站可能拥有独特的图片素材&#xff0c;为了防止其他网站通过直接链接图片URL的方式访问这些图片&#xff0c;网站管理员会采…

51c大模型~合集89

我自己的原文哦~ https://blog.51cto.com/whaosoft/12815167 #OpenAI很会营销 而号称超强AI营销的灵感岛实测成效如何&#xff1f; OpenAI 是懂营销的&#xff0c;连续 12 天发布&#xff0c;每天一个新花样&#xff0c;如今刚过一半&#xff0c;热度依旧不减。 毫无疑问&…

深度学习的unfold操作

unfold&#xff08;展开&#xff09;是深度学习框架中常见的数据操作。与我们熟悉的卷积类似&#xff0c;unfold也是使用一个特定大小的窗口和步长自左至右、自上至下滑动&#xff0c;不同的是&#xff0c;卷积是滑动后与核求乘积&#xff08;所以取名为卷积&#xff09;&#…

Jetpack Compose赋能:以速破局,高效打造非凡应用

Android Compose 是谷歌推出的一种现代化 UI 框架&#xff0c;基于 Kotlin 编程语言&#xff0c;旨在简化和加速 Android 应用开发。它以声明式编程为核心&#xff0c;与传统的 View 系统相比&#xff0c;Compose 提供了更直观、更简洁的开发体验。以下是对 Android Compose 的…

Dual-Write Problem 双写问题(微服务)

原文链接https://www.confluent.io/blog/dual-write-problem/ 双写问题发生于当两个外部系统必须以原子的方式更新时。 问题 说有人到银行存了一笔钱&#xff0c;触发 DepositFunds 命令&#xff0c;DepositFunds 命令被发送到Account microservice。 Account microservice需…

桥接模式的理解和实践

桥接模式&#xff08;Bridge Pattern&#xff09;&#xff0c;又称桥梁模式&#xff0c;是一种结构型设计模式。它的核心思想是将抽象部分与实现部分分离&#xff0c;使它们可以独立地进行变化&#xff0c;从而提高系统的灵活性和可扩展性。本文将详细介绍桥接模式的概念、原理…

kubeadm安装K8s集群之高可用组件keepalived+nginx及kubeadm部署

系列文章目录 1.kubeadm安装K8s集群之基础环境配置 2.kubeadm安装K8s集群之高可用组件keepalivednginx及kubeadm部署 3.kubeadm安装K8s集群之master节点加入 4.kubeadm安装K8s集群之worker1节点加入 kubeadm安装K8s集群之高可用组件keepalivednginx及kubeadm部署 1.安装kubeadm…

Avalonia实战实例三:实现可输入框的ComboBox控件

文章目录 一、Avalonia中的ComboBox控件二、更改Template&#xff0c;并添加水印 接着上篇关闭按钮实现登录界面 实现一个可输入&#xff0c;可下拉的用户名输入框 一、Avalonia中的ComboBox控件 Avalonia中Fluent主题里ComboBox实现&#xff1a; <ControlTheme x:Key&q…

TMS320C55x DSP芯片结构和CPU外围电路

第2章 DSP芯片结构和CPU外围电路 文章目录 第2章 DSP芯片结构和CPU外围电路TMS320C55x处理器的特点TMS320c55x CPU单元指令缓冲(Instruction Buffer Unit) I单元程序流程(Program Flow Unit) P单元地址数据(Address-data Flow Unit) A单元数据计算(Data Computation Unit) D单元…

Oracle 与 达梦 数据库 对比

当尝试安装了达梦数据库后&#xff0c;发现达梦真的和Oracle数据库太像了&#xff0c;甚至很多语法都相同。 比如&#xff1a;Oracle登录数据库采用sqlplus&#xff0c;达梦采用disql。 比如查看数据视图&#xff1a;达梦和Oracle都有 v$instance、v$database、dba_users等&a…

数据结构之五:排序

void*类型的实现&#xff1a;排序&#xff08;void*类型&#xff09;-CSDN博客 一、插入排序 1、直接插入排序 思想&#xff1a;把待排序的数据逐个插入到一个已经排好序的有序序列中&#xff0c;直到所有的记录插入完为止&#xff0c;得到一个新的有序序列 。 单趟&#x…

JavaWeb:JavaScript

学习 资源1 学习资源 2 黑马javaweb 1、引入方式 内部脚本&#xff1a; <script>内容</script> 外部脚本&#xff1a; <script src"js/test.js"></script> 2、基础语法 注释&#xff1a;// /* */ 结尾分号可有可无 大括号表示代码块 …