第20篇:Python 开发进阶:使用Django进行Web开发详解

第20篇:使用Django进行Web开发

内容简介

在上一篇文章中,我们深入探讨了Flask框架的高级功能,并通过构建一个博客系统展示了其实际应用。本篇文章将转向Django,另一个功能强大且广泛使用的Python Web框架。我们将介绍Django的核心概念,包括项目与应用结构、模型与数据库迁移、管理后台、模板与静态文件管理,以及如何将Django应用部署到生产环境。通过详细的代码示例和实战项目,您将掌握使用Django构建复杂且可扩展的Web应用的关键技能。


目录

  1. Django框架介绍
    • Django的历史与特点
    • Django的优势
    • 安装与设置
  2. 项目与应用结构
    • 创建Django项目
    • 理解项目与应用
    • 项目目录结构详解
  3. 模型与数据库迁移
    • 定义模型
    • 数据库配置
    • 执行迁移
    • 数据库操作
  4. 管理后台
    • 激活管理后台
    • 自定义管理界面
    • 权限与用户管理
  5. 模板与静态文件管理
    • Django模板引擎
    • 模板继承
    • 静态文件管理
    • 自定义模板标签与过滤器
  6. 部署Django应用
    • 选择部署平台
    • 使用Gunicorn和Nginx
    • 配置环境变量与安全设置
    • 启用HTTPS
  7. 示例项目:在线商店
    • 项目结构
    • 创建应用与定义模型
    • 实现用户认证
    • 产品管理与购物车功能
    • 订单处理与支付集成
  8. 常见问题及解决方法
    • 问题1:如何处理表单的CSRF保护?
    • 问题2:如何优化数据库查询性能?
    • 问题3:如何实现密码的安全存储?
    • 问题4:如何部署Django应用到生产环境?
  9. 总结

Django框架介绍

Django的历史与特点

Django是一个高级的Python Web框架,旨在快速开发和简化复杂、数据库驱动的网站的构建过程。由Adrian HolovatySimon Willison在2003年开发,并于2005年正式发布,Django以其“务实”而闻名,遵循“不要重复自己”(DRY)和“显式优于隐式”的设计原则。

主要特点

  • 快速开发:提供了大量内置功能,减少开发时间。
  • 可扩展性:适用于从简单的博客到复杂的企业级应用。
  • 安全性:内置多种安全保护机制,防范常见的Web攻击。
  • 完善的文档:拥有详尽的官方文档和活跃的社区支持。
  • 内置管理后台:自动生成的管理界面,方便数据管理。

Django的优势

  1. 全栈框架:Django涵盖了从前端到后端的各个方面,无需依赖大量第三方库。
  2. ORM(对象关系映射):简化数据库操作,支持多种数据库后端。
  3. 模板系统:强大的模板引擎,支持模板继承和自定义标签。
  4. 表单处理:自动生成表单,并提供丰富的表单验证功能。
  5. URL路由:灵活的URL配置,支持正则表达式和命名空间。
  6. 中间件:支持请求和响应处理的中间件,便于功能扩展。
  7. 社区与生态系统:拥有大量的第三方包和插件,满足各种需求。

安装与设置

安装Django

使用pip安装Django是最常见的方法。确保您已经安装了Python和pip

pip install Django

验证安装

安装完成后,可以通过以下命令验证Django是否成功安装:

django-admin --version

创建Django项目

创建项目

使用django-admin工具创建一个新的Django项目。

django-admin startproject mysite

运行开发服务器

进入项目目录并运行开发服务器。

cd mysite
python manage.py runserver

在浏览器中访问http://127.0.0.1:8000/,您将看到Django的欢迎页面,表明项目已成功创建并运行。


项目与应用结构

创建Django项目

Django项目是一个包含多个应用的集合,负责整体配置和协调。每个项目可以包含一个或多个应用,每个应用负责特定的功能模块。

django-admin startproject mysite
cd mysite

理解项目与应用

  • 项目(Project):整个Web应用的容器,包含全局配置、URL路由和应用的集合。
  • 应用(App):项目中的一个独立模块,负责特定功能,如用户管理、博客、商店等。

项目目录结构详解

创建项目后,您将看到以下目录结构:

mysite/
├── manage.py
├── mysite/
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py

文件说明

  • manage.py:Django的命令行工具,用于执行各种任务,如运行开发服务器、数据库迁移等。
  • mysite/:项目的核心目录,包含全局配置文件。
    • init.py:将该目录标识为Python包。
    • settings.py:项目的配置文件,包含数据库配置、已安装的应用、静态文件配置等。
    • urls.py:全局URL路由配置,定义URL与视图的对应关系。
    • wsgi.py:WSGI兼容的Web服务器网关接口,用于部署。

创建应用

使用manage.py创建一个新的应用,例如创建一个名为blog的应用。

python manage.py startapp blog

更新项目配置

settings.py中添加新创建的应用到INSTALLED_APPS列表。

# mysite/settings.pyINSTALLED_APPS = [...'blog',
]

项目目录结构扩展

创建应用后,项目目录结构如下:

mysite/
├── manage.py
├── mysite/
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── blog/├── __init__.py├── admin.py├── apps.py├── migrations/│   └── __init__.py├── models.py├── tests.py└── views.py

文件说明

  • admin.py:用于注册模型到Django管理后台。
  • apps.py:应用的配置文件。
  • migrations/:数据库迁移文件夹,用于记录模型的变化。
  • models.py:定义应用的数据模型。
  • tests.py:编写测试用例。
  • views.py:定义视图函数或类视图,处理请求和返回响应。

模型与数据库迁移

定义模型

Django的**模型(Models)**是用Python类定义的,代表数据库中的数据结构。每个模型类继承自django.db.models.Model

示例模型

blog/models.py中定义一个简单的博客文章模型。

# blog/models.py
from django.db import models
from django.contrib.auth.models import Userclass Post(models.Model):title = models.CharField(max_length=200)content = models.TextField()date_posted = models.DateTimeField(auto_now_add=True)author = models.ForeignKey(User, on_delete=models.CASCADE)def __str__(self):return self.title

字段说明

  • title:文章标题,字符型,最大长度200。
  • content:文章内容,文本型。
  • date_posted:文章发布时间,自动设置为创建时的时间。
  • author:文章作者,外键关联到Django内置的用户模型。

数据库配置

默认情况下,Django使用SQLite作为数据库。可以在settings.py中更改数据库配置,以使用其他数据库如PostgreSQL、MySQL等。

示例:配置PostgreSQL

# mysite/settings.pyDATABASES = {'default': {'ENGINE': 'django.db.backends.postgresql','NAME': 'mydatabase','USER': 'mydatabaseuser','PASSWORD': 'mypassword','HOST': 'localhost','PORT': '5432',}
}

安装相应的数据库驱动

对于PostgreSQL,需要安装psycopg2

pip install psycopg2

执行迁移

定义模型后,需要创建数据库表。这通过Django的迁移系统完成。

  1. 创建迁移文件

    python manage.py makemigrations
    

    该命令会根据模型的变化生成迁移文件,记录数据库结构的变化。

  2. 应用迁移

    python manage.py migrate
    

    该命令会将迁移应用到数据库,创建或修改相应的表。

数据库操作

Django提供了强大的ORM(对象关系映射)工具,简化了数据库操作。

创建新记录

# 在Django shell中操作
python manage.py shell
from blog.models import Post
from django.contrib.auth.models import User# 获取用户
user = User.objects.get(username='john')# 创建新文章
post = Post(title='我的第一篇博客', content='这是博客内容。', author=user)
post.save()

查询数据

# 获取所有文章
posts = Post.objects.all()# 过滤查询
john_posts = Post.objects.filter(author__username='john')# 获取单个对象
post = Post.objects.get(id=1)

更新数据

post = Post.objects.get(id=1)
post.title = '更新后的标题'
post.save()

删除数据

post = Post.objects.get(id=1)
post.delete()

管理后台

激活管理后台

Django自带一个功能强大的管理后台,用于管理数据库中的数据。要激活管理后台,需要进行以下步骤。

  1. 创建超级用户

    python manage.py createsuperuser
    

    按提示输入用户名、电子邮件和密码,创建一个超级用户。

  2. 注册模型到管理后台

    blog/admin.py中注册模型。

    # blog/admin.py
    from django.contrib import admin
    from .models import Postadmin.site.register(Post)
    
  3. 运行开发服务器并访问管理后台

    python manage.py runserver
    

    在浏览器中访问http://127.0.0.1:8000/admin/,使用超级用户的凭据登录。您将看到已注册的Post模型,可以在管理后台中添加、编辑和删除文章。

自定义管理界面

可以自定义管理界面以更好地展示和管理数据。

示例:自定义Post模型的管理界面

# blog/admin.py
from django.contrib import admin
from .models import Postclass PostAdmin(admin.ModelAdmin):list_display = ('title', 'author', 'date_posted')search_fields = ('title', 'content')list_filter = ('date_posted', 'author')admin.site.register(Post, PostAdmin)

功能说明

  • list_display:在列表视图中显示的字段。
  • search_fields:启用搜索功能的字段。
  • list_filter:侧边栏的过滤选项。

权限与用户管理

Django的管理后台不仅用于数据管理,还支持权限和用户管理。

用户和组管理

在管理后台,可以创建和管理用户和组,分配不同的权限。

  1. 创建用户:在管理后台的“Users”部分创建新用户。
  2. 分配权限:为用户分配特定的权限,如添加、修改或删除某些模型。
  3. 创建组:将权限分配给组,然后将用户添加到组,简化权限管理。

示例:限制用户只能管理自己的文章

通过自定义ModelAdmin类,可以限制用户只能看到和管理自己的数据。

# blog/admin.py
from django.contrib import admin
from .models import Postclass PostAdmin(admin.ModelAdmin):list_display = ('title', 'author', 'date_posted')search_fields = ('title', 'content')list_filter = ('date_posted', 'author')def get_queryset(self, request):qs = super().get_queryset(request)if request.user.is_superuser:return qsreturn qs.filter(author=request.user)def save_model(self, request, obj, form, change):if not obj.pk:obj.author = request.userobj.save()admin.site.register(Post, PostAdmin)

功能说明

  • get_queryset:限制查询集,普通用户只能看到自己的文章。
  • save_model:在保存新文章时,自动将当前用户设置为作者。

模板与静态文件管理

Django模板引擎

Django使用自己的模板引擎,允许在HTML中嵌入动态内容。模板引擎支持变量、标签和过滤器,帮助生成动态页面。

基本模板示例

创建一个简单的模板blog/templates/blog/home.html

<!-- blog/templates/blog/home.html -->
<!DOCTYPE html>
<html>
<head><title>博客首页</title>
</head>
<body><h1>欢迎来到我的博客</h1><ul>{% for post in posts %}<li><a href="{% url 'blog:post_detail' post.id %}">{{ post.title }}</a> by {{ post.author.username }}</li>{% empty %}<li>暂无文章。</li>{% endfor %}</ul>
</body>
</html>

模板继承

模板继承允许定义一个基础模板,并在此基础上创建子模板,避免重复代码。

创建基础模板

创建templates/base.html

<!-- templates/base.html -->
<!DOCTYPE html>
<html>
<head><title>{% block title %}我的网站{% endblock %}</title><link rel="stylesheet" href="{% static 'css/styles.css' %}">
</head>
<body><header><h1>我的网站</h1><nav><a href="{% url 'blog:home' %}">首页</a> |<a href="{% url 'admin:index' %}">管理后台</a></nav></header><main>{% block content %}{% endblock %}</main><footer><p>&copy; 2025 我的公司</p></footer>
</body>
</html>

创建子模板

修改blog/templates/blog/home.html,继承自base.html

<!-- blog/templates/blog/home.html -->
{% extends 'base.html' %}{% block title %}博客首页{% endblock %}{% block content %}<h2>博客文章</h2><ul>{% for post in posts %}<li><a href="{% url 'blog:post_detail' post.id %}">{{ post.title }}</a> by {{ post.author.username }}</li>{% empty %}<li>暂无文章。</li>{% endfor %}</ul>
{% endblock %}

静态文件管理

Django管理静态文件(如CSS、JavaScript、图片)通过STATICFILES系统处理。需要在settings.py中配置静态文件相关设置。

配置静态文件

# mysite/settings.pySTATIC_URL = '/static/'
STATICFILES_DIRS = [BASE_DIR / "static"]

使用静态文件

在模板中加载静态文件。

{% load static %}<!DOCTYPE html>
<html>
<head><title>使用静态文件</title><link rel="stylesheet" href="{% static 'css/styles.css' %}">
</head>
<body><!-- 页面内容 -->
</body>
</html>

收集静态文件

在生产环境中,使用collectstatic命令将所有静态文件收集到一个目录。

python manage.py collectstatic

自定义模板标签与过滤器

可以创建自定义的模板标签和过滤器,扩展模板引擎的功能。

创建自定义过滤器

  1. 创建模板标签目录

    在应用目录下创建templatetags文件夹,并添加__init__.py

    blog/
    ├── templatetags/
    │   ├── __init__.py
    │   └── blog_extras.py
    
  2. 定义过滤器

    # blog/templatetags/blog_extras.py
    from django import templateregister = template.Library()@register.filter(name='truncate')
    def truncate(value, arg):"""Truncate the string after a certain number of characters."""try:length = int(arg)except ValueError:return valueif len(value) > length:return value[:length] + '...'return value
    
  3. 使用过滤器

    在模板中加载并使用自定义过滤器。

    {% load blog_extras %}<p>{{ post.content|truncate:100 }}</p>
    

创建自定义标签

类似于过滤器,可以创建自定义标签以实现复杂的逻辑。

# blog/templatetags/blog_extras.py
from django import templateregister = template.Library()@register.simple_tag
def current_time(format_string):from django.utils import timezonereturn timezone.now().strftime(format_string)

使用自定义标签

{% load blog_extras %}<p>当前时间:{% current_time "%Y-%m-%d %H:%M" %}</p>

部署Django应用

选择部署平台

部署Django应用时,可以选择多种平台,包括:

  • 虚拟私有服务器(VPS):如DigitalOcean、Linode、AWS EC2。
  • 平台即服务(PaaS):如Heroku、PythonAnywhere、Google App Engine。
  • 容器化平台:如Docker、Kubernetes。

使用Gunicorn和Nginx

Gunicorn是一个Python WSGI HTTP服务器,适用于部署Django应用。Nginx作为反向代理服务器,处理客户端请求并转发给Gunicorn。

步骤

  1. 安装Gunicorn

    pip install gunicorn
    
  2. 运行Gunicorn

    在项目根目录下运行Gunicorn。

    gunicorn mysite.wsgi:application
    
  3. 配置Nginx

    创建一个Nginx配置文件,配置反向代理。

    # /etc/nginx/sites-available/mysiteserver {listen 80;server_name your_domain.com;location = /favicon.ico { access_log off; log_not_found off; }location /static/ {root /path/to/your/mysite;}location / {proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $scheme;proxy_pass http://127.0.0.1:8000;}
    }
    

    启用配置并重启Nginx。

    sudo ln -s /etc/nginx/sites-available/mysite /etc/nginx/sites-enabled
    sudo nginx -t
    sudo systemctl restart nginx
    
  4. 运行Gunicorn作为后台服务

    使用systemd创建一个服务文件。

    # /etc/systemd/system/gunicorn.service[Unit]
    Description=gunicorn daemon for Django project
    After=network.target[Service]
    User=youruser
    Group=www-data
    WorkingDirectory=/path/to/your/mysite
    ExecStart=/path/to/your/venv/bin/gunicorn mysite.wsgi:application --bind 127.0.0.1:8000[Install]
    WantedBy=multi-user.target
    

    启动并启用Gunicorn服务。

    sudo systemctl start gunicorn
    sudo systemctl enable gunicorn
    

配置环境变量与安全设置

配置环境变量

不要在代码中硬编码敏感信息。使用环境变量管理配置。

  1. 安装python-decouple

    pip install python-decouple
    
  2. 修改settings.py

    # mysite/settings.py
    from decouple import configSECRET_KEY = config('SECRET_KEY')
    DEBUG = config('DEBUG', default=False, cast=bool)DATABASES = {'default': {'ENGINE': 'django.db.backends.postgresql','NAME': config('DB_NAME'),'USER': config('DB_USER'),'PASSWORD': config('DB_PASSWORD'),'HOST': config('DB_HOST'),'PORT': config('DB_PORT', default='5432'),}
    }
    
  3. 创建.env文件

    # .env
    SECRET_KEY=your_production_secret_key
    DEBUG=False
    DB_NAME=your_db_name
    DB_USER=your_db_user
    DB_PASSWORD=your_db_password
    DB_HOST=localhost
    DB_PORT=5432
    

    注意:确保.env文件不被版本控制系统(如Git)跟踪。

安全设置

  1. 禁用调试模式

    在生产环境中,确保DEBUG=False

  2. 设置允许的主机

    settings.py中配置ALLOWED_HOSTS

    ALLOWED_HOSTS = ['your_domain.com', 'www.your_domain.com']
    
  3. 使用HTTPS

    配置SSL证书,启用HTTPS,确保数据传输安全。

  4. 配置安全中间件

    确保以下中间件在MIDDLEWARE中启用,以增强安全性。

    MIDDLEWARE = ['django.middleware.security.SecurityMiddleware','whitenoise.middleware.WhiteNoiseMiddleware',  # 用于静态文件管理...
    ]
    

启用HTTPS

使用Let’s Encrypt获取免费的SSL证书,并配置Nginx以启用HTTPS。

  1. 安装Certbot

    sudo apt-get update
    sudo apt-get install certbot python3-certbot-nginx
    
  2. 获取证书

    sudo certbot --nginx -d your_domain.com -d www.your_domain.com
    
  3. 自动续期

    Certbot自动配置证书续期。可以手动测试续期。

    sudo certbot renew --dry-run
    

更新Nginx配置

Certbot会自动修改Nginx配置以启用HTTPS。确保配置正确,并重启Nginx。

sudo systemctl restart nginx

示例项目:在线商店

为了综合应用上述知识,本节将带您构建一个功能完善的在线商店,包含用户注册与登录、产品管理、购物车功能及订单处理。

项目结构

online_store/
├── manage.py
├── online_store/
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── store/
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── migrations/
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── templates/
│   ├── base.html
│   ├── store/
│   │   ├── home.html
│   │   ├── product_detail.html
│   │   └── cart.html
└── static/└── css/└── styles.css

创建应用与定义模型

创建应用

python manage.py startapp store

定义模型

store/models.py中定义ProductOrder模型。

# store/models.py
from django.db import models
from django.contrib.auth.models import Userclass Product(models.Model):name = models.CharField(max_length=200)description = models.TextField()price = models.DecimalField(max_digits=10, decimal_places=2)stock = models.PositiveIntegerField()image = models.ImageField(upload_to='product_images/', blank=True, null=True)def __str__(self):return self.nameclass Order(models.Model):user = models.ForeignKey(User, on_delete=models.CASCADE)ordered_date = models.DateTimeField(auto_now_add=True)is_completed = models.BooleanField(default=False)def __str__(self):return f'Order {self.id} by {self.user.username}'class OrderItem(models.Model):order = models.ForeignKey(Order, related_name='items', on_delete=models.CASCADE)product = models.ForeignKey(Product, on_delete=models.CASCADE)quantity = models.PositiveIntegerField(default=1)def __str__(self):return f'{self.quantity} of {self.product.name}'

执行迁移

python manage.py makemigrations
python manage.py migrate

实现用户认证

Django内置了用户认证系统,可以利用其功能实现用户注册与登录。

创建注册表单

store/forms.py中定义用户注册表单。

# store/forms.py
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationFormclass UserRegisterForm(UserCreationForm):email = forms.EmailField(required=True)class Meta:model = Userfields = ['username', 'email', 'password1', 'password2']

创建视图

store/views.py中添加注册和登录视图。

# store/views.py
from django.shortcuts import render, redirect
from django.contrib import messages
from django.contrib.auth import login, authenticate, logout
from .forms import UserRegisterForm
from django.contrib.auth.forms import AuthenticationFormdef register(request):if request.method == 'POST':form = UserRegisterForm(request.POST)if form.is_valid():user = form.save()messages.success(request, f'账户 {user.username} 创建成功!请登录。')return redirect('login')else:form = UserRegisterForm()return render(request, 'store/register.html', {'form': form})def user_login(request):if request.method == 'POST':form = AuthenticationForm(request, data=request.POST)if form.is_valid():username = form.cleaned_data.get('username')password = form.cleaned_data.get('password')user = authenticate(username=username, password=password)if user is not None:login(request, user)messages.info(request, f'您已登录为 {username}.')return redirect('home')else:messages.error(request, '无效的用户名或密码。')else:messages.error(request, '无效的用户名或密码。')else:form = AuthenticationForm()return render(request, 'store/login.html', {'form': form})def user_logout(request):logout(request)messages.info(request, '您已成功注销。')return redirect('home')

配置URL

store/urls.py中定义应用的URL。

# store/urls.py
from django.urls import path
from . import viewsurlpatterns = [path('register/', views.register, name='register'),path('login/', views.user_login, name='login'),path('logout/', views.user_logout, name='logout'),
]

在项目的主URL配置中包含应用的URL。

# online_store/urls.py
from django.contrib import admin
from django.urls import path, includeurlpatterns = [path('admin/', admin.site.urls),path('', include('store.urls')),
]

创建模板

创建store/templates/store/register.htmlstore/templates/store/login.html

<!-- store/templates/store/register.html -->
{% extends 'base.html' %}
{% load static %}{% block title %}注册{% endblock %}{% block content %}<h2>注册</h2><form method="POST">{% csrf_token %}{{ form.as_p }}<button type="submit">注册</button></form>
{% endblock %}
<!-- store/templates/store/login.html -->
{% extends 'base.html' %}
{% load static %}{% block title %}登录{% endblock %}{% block content %}<h2>登录</h2><form method="POST">{% csrf_token %}{{ form.as_p }}<button type="submit">登录</button></form>
{% endblock %}

更新基础模板

templates/base.html中添加导航链接。

<!-- templates/base.html -->
<!DOCTYPE html>
<html>
<head><title>{% block title %}在线商店{% endblock %}</title><link rel="stylesheet" href="{% static 'css/styles.css' %}">
</head>
<body><header><h1>在线商店</h1><nav><a href="{% url 'home' %}">首页</a> |{% if user.is_authenticated %}<a href="{% url 'logout' %}">注销</a>{% else %}<a href="{% url 'login' %}">登录</a> |<a href="{% url 'register' %}">注册</a>{% endif %}</nav></header><main>{% if messages %}<ul>{% for message in messages %}<li>{{ message }}</li>{% endfor %}</ul>{% endif %}{% block content %}{% endblock %}</main><footer><p>&copy; 2025 在线商店</p></footer>
</body>
</html>

产品管理与购物车功能

定义视图

store/views.py中添加首页和产品详情视图。

# store/views.py
from django.shortcuts import render, get_object_or_404
from .models import Productdef home(request):products = Product.objects.all()return render(request, 'store/home.html', {'products': products})def product_detail(request, pk):product = get_object_or_404(Product, pk=pk)return render(request, 'store/product_detail.html', {'product': product})

更新URL

# store/urls.py
from django.urls import path
from . import viewsurlpatterns = [path('', views.home, name='home'),path('product/<int:pk>/', views.product_detail, name='product_detail'),path('register/', views.register, name='register'),path('login/', views.user_login, name='login'),path('logout/', views.user_logout, name='logout'),
]

创建模板

<!-- store/templates/store/home.html -->
{% extends 'base.html' %}
{% load static %}{% block title %}首页{% endblock %}{% block content %}<h2>产品列表</h2><ul>{% for product in products %}<li><a href="{% url 'product_detail' product.pk %}">{{ product.name }}</a> - ${{ product.price }}</li>{% empty %}<li>暂无产品。</li>{% endfor %}</ul>
{% endblock %}
<!-- store/templates/store/product_detail.html -->
{% extends 'base.html' %}
{% load static %}{% block title %}{{ product.name }}{% endblock %}{% block content %}<h2>{{ product.name }}</h2><p>{{ product.description }}</p><p>价格:${{ product.price }}</p><p>库存:{{ product.stock }}</p>{% if user.is_authenticated %}<form method="POST" action="{% url 'add_to_cart' product.pk %}">{% csrf_token %}<button type="submit">加入购物车</button></form>{% else %}<p><a href="{% url 'login' %}">登录</a>后可添加到购物车。</p>{% endif %}
{% endblock %}

实现购物车功能

购物车可以通过会话(Session)管理。

添加购物车视图

# store/views.py
from django.shortcuts import redirectdef add_to_cart(request, pk):product = get_object_or_404(Product, pk=pk)cart = request.session.get('cart', {})if str(pk) in cart:cart[str(pk)] += 1else:cart[str(pk)] = 1request.session['cart'] = cartmessages.success(request, f'已将 {product.name} 添加到购物车。')return redirect('home')def view_cart(request):cart = request.session.get('cart', {})cart_items = []total = 0for pk, quantity in cart.items():product = get_object_or_404(Product, pk=pk)total += product.price * quantitycart_items.append({'product': product,'quantity': quantity,'total_price': product.price * quantity})return render(request, 'store/cart.html', {'cart_items': cart_items, 'total': total})

更新URL

# store/urls.py
urlpatterns = [path('', views.home, name='home'),path('product/<int:pk>/', views.product_detail, name='product_detail'),path('add_to_cart/<int:pk>/', views.add_to_cart, name='add_to_cart'),path('cart/', views.view_cart, name='cart'),path('register/', views.register, name='register'),path('login/', views.user_login, name='login'),path('logout/', views.user_logout, name='logout'),
]

创建购物车模板

<!-- store/templates/store/cart.html -->
{% extends 'base.html' %}
{% load static %}{% block title %}购物车{% endblock %}{% block content %}<h2>购物车</h2>{% if cart_items %}<ul>{% for item in cart_items %}<li>{{ item.product.name }} - ${{ item.product.price }} x {{ item.quantity }} = ${{ item.total_price }}</li>{% endfor %}</ul><p>总计:${{ total }}</p><a href="{% url 'checkout' %}">结账</a>{% else %}<p>购物车为空。</p>{% endif %}
{% endblock %}

订单处理与支付集成

定义订单视图

store/views.py中添加结账视图。

# store/views.py
from django.contrib.auth.decorators import login_required@login_required
def checkout(request):cart = request.session.get('cart', {})if not cart:messages.error(request, '购物车为空。')return redirect('home')order = Order.objects.create(user=request.user)for pk, quantity in cart.items():product = get_object_or_404(Product, pk=pk)if product.stock < quantity:messages.error(request, f'产品 {product.name} 库存不足。')return redirect('cart')OrderItem.objects.create(order=order, product=product, quantity=quantity)product.stock -= quantityproduct.save()# 清空购物车request.session['cart'] = {}messages.success(request, '订单已创建成功!')return redirect('home')

更新URL

# store/urls.py
urlpatterns = [path('', views.home, name='home'),path('product/<int:pk>/', views.product_detail, name='product_detail'),path('add_to_cart/<int:pk>/', views.add_to_cart, name='add_to_cart'),path('cart/', views.view_cart, name='cart'),path('checkout/', views.checkout, name='checkout'),path('register/', views.register, name='register'),path('login/', views.user_login, name='login'),path('logout/', views.user_logout, name='logout'),
]

集成支付网关

可以集成第三方支付网关(如Stripe、PayPal)处理支付。以下是集成Stripe的简要示例。

  1. 安装Stripe库

    pip install stripe
    
  2. 配置Stripe

    settings.py中添加Stripe的API密钥。

    # mysite/settings.py
    STRIPE_PUBLIC_KEY = config('STRIPE_PUBLIC_KEY')
    STRIPE_SECRET_KEY = config('STRIPE_SECRET_KEY')
    
  3. 创建支付视图

    # store/views.py
    import stripe
    from django.conf import settingsstripe.api_key = settings.STRIPE_SECRET_KEY@login_required
    def payment(request):if request.method == 'POST':token = request.POST.get('stripeToken')try:charge = stripe.Charge.create(amount=int(request.POST['amount']) * 100,  # 转换为分currency='usd',description='在线商店订单',source=token,)messages.success(request, '支付成功!')return redirect('home')except stripe.error.CardError as e:messages.error(request, '支付失败:{}'.format(e))return render(request, 'store/payment.html', {'stripe_public_key': settings.STRIPE_PUBLIC_KEY})
    
  4. 更新URL

    # store/urls.py
    urlpatterns = [...path('payment/', views.payment, name='payment'),
    ]
    
  5. 创建支付模板

    <!-- store/templates/store/payment.html -->
    {% extends 'base.html' %}
    {% load static %}{% block title %}支付{% endblock %}{% block content %}<h2>支付</h2><form action="{% url 'payment' %}" method="POST">{% csrf_token %}<script src="https://checkout.stripe.com/checkout.js" class="stripe-button"data-key="{{ stripe_public_key }}"data-amount="5000"data-name="在线商店"data-description="订单支付"data-currency="usd"data-email="{{ user.email }}"></script></form>
    {% endblock %}
    

注意:此示例仅为基本集成,实际应用中需要处理更复杂的支付流程和安全性措施。


常见问题及解决方法

问题1:如何处理表单的CSRF保护?

原因:跨站请求伪造(CSRF)是一种常见的Web攻击,Django通过生成和验证CSRF令牌来防止此类攻击。

解决方法

  1. 启用CSRF保护

    Django默认启用了CSRF中间件。确保MIDDLEWARE中包含'django.middleware.csrf.CsrfViewMiddleware'

    # mysite/settings.py
    MIDDLEWARE = [...'django.middleware.csrf.CsrfViewMiddleware',...
    ]
    
  2. 在表单中包含CSRF令牌

    在模板中的表单标签内添加{% csrf_token %}

    <form method="POST" action="{% url 'some_view' %}">{% csrf_token %}<!-- 表单字段 -->
    </form>
    
  3. 处理Ajax请求的CSRF

    对于Ajax请求,需要在请求头中包含CSRF令牌。可以在JavaScript中通过Cookie获取CSRF令牌并设置请求头。

    function getCookie(name) {let cookieValue = null;if (document.cookie && document.cookie !== '') {const cookies = document.cookie.split(';');for (let i = 0; i < cookies.length; i++) {const cookie = cookies[i].trim();// Does this cookie string begin with the name we want?if (cookie.substring(0, name.length + 1) === (name + '=')) {cookieValue = decodeURIComponent(cookie.substring(name.length + 1));break;}}}return cookieValue;
    }
    const csrftoken = getCookie('csrftoken');fetch('/some_url/', {method: 'POST',headers: {'X-CSRFToken': csrftoken,'Content-Type': 'application/json'},body: JSON.stringify({ /* 数据 */ })
    });
    

问题2:如何优化数据库查询性能?

原因:在处理大量数据时,未优化的查询可能导致性能瓶颈,影响应用响应速度。

解决方法

  1. 使用select_relatedprefetch_related

    这些方法可以减少数据库查询次数,优化关联对象的获取。

    # 使用select_related获取关联的外键对象
    posts = Post.objects.select_related('author').all()# 使用prefetch_related获取多对多或反向外键对象
    orders = Order.objects.prefetch_related('items__product').all()
    
  2. 添加数据库索引

    为频繁查询的字段添加索引,提高查询速度。

    # store/models.py
    class Product(models.Model):name = models.CharField(max_length=200, db_index=True)# 其他字段
    
  3. 分页查询

    对大量数据进行分页展示,减少单次查询的数据量。

    from django.core.paginator import Paginatordef home(request):products_list = Product.objects.all()paginator = Paginator(products_list, 10)  # 每页10个page_number = request.GET.get('page')page_obj = paginator.get_page(page_number)return render(request, 'store/home.html', {'page_obj': page_obj})
    

    在模板中显示分页链接:

    <!-- store/templates/store/home.html -->
    <ul>{% for product in page_obj %}<li>{{ product.name }} - ${{ product.price }}</li>{% endfor %}
    </ul><div class="pagination"><span class="page-links">{% if page_obj.has_previous %}<a href="?page=1">&laquo; 第一页</a><a href="?page={{ page_obj.previous_page_number }}">上一页</a>{% endif %}<span class="current">第 {{ page_obj.number }} 页,共 {{ page_obj.paginator.num_pages }} 页</span>{% if page_obj.has_next %}<a href="?page={{ page_obj.next_page_number }}">下一页</a><a href="?page={{ page_obj.paginator.num_pages }}">最后一页 &raquo;</a>{% endif %}</span>
    </div>
    
  4. 使用缓存

    利用Django的缓存框架缓存频繁访问的数据,减少数据库查询次数。

    from django.core.cache import cachedef home(request):products = cache.get('all_products')if not products:products = Product.objects.all()cache.set('all_products', products, 300)  # 缓存5分钟return render(request, 'store/home.html', {'products': products})
    
  5. 优化查询集

    仅获取需要的字段,减少数据传输量。

    products = Product.objects.only('name', 'price')
    
  6. 使用原生SQL查询

    在复杂查询场景下,使用原生SQL语句可能比ORM查询更高效。

    from django.db import connectiondef get_custom_data():with connection.cursor() as cursor:cursor.execute("SELECT name, price FROM store_product WHERE stock > %s", [10])row = cursor.fetchall()return row
    

问题3:如何实现密码的安全存储?

原因:用户密码的安全存储对于保护用户隐私和防止数据泄露至关重要。

解决方法

  1. 使用Django内置的用户模型

    Django的User模型已经实现了密码的哈希存储,确保密码的安全性。

    from django.contrib.auth.models import Useruser = User.objects.create_user(username='john', email='john@example.com', password='password123')
    
  2. 密码哈希算法

    Django使用强大的哈希算法(如PBKDF2)和盐(Salt)自动处理密码的加密和存储。

    # 验证密码
    user = User.objects.get(username='john')
    user.check_password('password123')  # 返回True或False
    
  3. 自定义用户模型(可选):

    如果需要扩展用户模型,可以创建自定义的用户模型,并确保继承自AbstractBaseUserPermissionsMixin,以保持安全性。

    # accounts/models.py
    from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
    from django.db import modelsclass CustomUser(AbstractBaseUser, PermissionsMixin):email = models.EmailField(unique=True)# 其他字段USERNAME_FIELD = 'email'REQUIRED_FIELDS = []
    

    注意:在创建自定义用户模型时,应尽早进行,以避免迁移和兼容性问题。

  4. 定期更新密码哈希算法

    随着技术的发展,Django会定期更新默认的密码哈希算法。可以通过PASSWORD_HASHERS设置自定义哈希器。

    # mysite/settings.py
    PASSWORD_HASHERS = ['django.contrib.auth.hashers.PBKDF2PasswordHasher','django.contrib.auth.hashers.Argon2PasswordHasher','django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
    ]
    
  5. 强密码策略

    通过配置密码验证器,强制用户设置强密码。

    # mysite/settings.py
    AUTH_PASSWORD_VALIDATORS = [{'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',},{'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator','OPTIONS': {'min_length': 8,}},{'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',},{'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',},
    ]
    

问题4:如何部署Django应用到生产环境?

原因:开发环境与生产环境存在差异,直接在生产环境中运行Django开发服务器不安全且不高效。

解决方法

  1. 使用WSGI服务器

    部署Django应用时,应使用专业的WSGI服务器,如Gunicorn或uWSGI。

    # 使用Gunicorn
    pip install gunicorn
    gunicorn online_store.wsgi:application
    
  2. 配置反向代理

    使用Nginx或Apache作为反向代理服务器,处理客户端请求并转发给WSGI服务器。

    Nginx示例配置

    server {listen 80;server_name your_domain.com;location / {proxy_pass http://127.0.0.1:8000;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $scheme;}location /static/ {alias /path/to/your/online_store/static/;}location /media/ {alias /path/to/your/online_store/media/;}
    }
    
  3. 启用HTTPS

    使用SSL证书为您的网站启用HTTPS,提高数据传输的安全性。可以使用Let’s Encrypt免费获取SSL证书。

  4. 配置环境变量

    不要将敏感信息(如SECRET_KEY、数据库URI)硬编码在代码中,而应通过环境变量配置。

    export DJANGO_SECRET_KEY='your_production_secret_key'
    export DJANGO_DEBUG=False
    export DB_NAME='your_db_name'
    export DB_USER='your_db_user'
    export DB_PASSWORD='your_db_password'
    export DB_HOST='your_db_host'
    export DB_PORT='your_db_port'
    

    并在settings.py中使用这些变量。

  5. 日志管理

    配置日志记录,监控应用的运行状态和错误信息。

    # mysite/settings.py
    LOGGING = {'version': 1,'disable_existing_loggers': False,'handlers': {'file': {'level': 'DEBUG','class': 'logging.FileHandler','filename': '/path/to/your/logs/debug.log',},},'loggers': {'django': {'handlers': ['file'],'level': 'DEBUG','propagate': True,},},
    }
    
  6. 使用容器化

    使用Docker等容器技术,简化部署过程,提高环境一致性。

    Dockerfile示例

    FROM python:3.9-slimENV PYTHONUNBUFFERED 1WORKDIR /appCOPY requirements.txt /app/
    RUN pip install --no-cache-dir -r requirements.txtCOPY . /app/CMD ["gunicorn", "online_store.wsgi:application", "--bind", "0.0.0.0:8000"]
    

    构建与运行容器

    docker build -t online_store .
    docker run -d -p 8000:8000 online_store
    
  7. 定期备份

    定期备份数据库和重要数据,确保数据安全。

  8. 监控与维护

    使用监控工具(如Prometheus、Grafana)监控应用性能,及时发现并解决问题。


总结

在本篇文章中,我们深入探讨了Django框架的核心概念和高级功能,包括项目与应用结构、模型与数据库迁移、管理后台、模板与静态文件管理,以及如何将Django应用部署到生产环境。通过构建一个在线商店的实战项目,您已经掌握了使用Django构建复杂且可扩展的Web应用所需的关键技能。

学习建议

  1. 扩展功能:尝试为在线商店添加更多功能,如用户评价、产品分类、搜索功能等,进一步巩固所学知识。
  2. 探索Django REST框架:学习如何使用Django REST框架构建RESTful API,扩展应用的功能和可用性。
  3. 优化性能:研究Django应用的性能优化技巧,如缓存策略、数据库优化、异步任务处理等。
  4. 增强安全性:深入了解Web应用的安全性,学习防范常见的安全漏洞,如SQL注入、XSS攻击等。
  5. 持续部署与运维:学习如何实现持续集成和持续部署(CI/CD),提升开发和部署效率。
  6. 参与社区:通过参与Django相关的开源项目和社区活动,学习业界最佳实践,提升编程和协作能力。
  7. 深入学习:阅读官方文档和相关书籍,如《Two Scoops of Django》以进一步提升Django开发技能。

如果您有任何问题或需要进一步的帮助,请随时在评论区留言或联系相关技术社区。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

电力场效应晶体管(电力 MOSFET),全控型器件

电力场效应晶体管&#xff08;Power MOSFET&#xff09;属于全控型器件是一种电压触发的电力电子器件&#xff0c;一种载流子导电&#xff08;单极性器件&#xff09;一个器件是由一个个小的mosfet组成以下是相关介绍&#xff1a; 工作原理&#xff08;栅极电压控制漏极电流&a…

Spring Boot整合JavaMail实现邮件发送

一. 发送邮件原理 发件人【设置授权码】 - SMTP协议【Simple Mail TransferProtocol - 是一种提供可靠且有效的电子邮件传输的协议】 - 收件人 二. 获取授权码 开通POP3/SMTP&#xff0c;获取授权码 授权码是QQ邮箱推出的&#xff0c;用于登录第三方客户端的专用密码。适用…

PHP防伪溯源一体化管理系统小程序

&#x1f50d; 防伪溯源一体化管理系统&#xff0c;品质之光&#xff0c;根源之锁 &#x1f680; 引领防伪技术革命&#xff0c;重塑品牌信任基石 我们自豪地站在防伪技术的前沿&#xff0c;为您呈现基于ThinkPHP和Uniapp精心锻造的多平台&#xff08;微信小程序、H5网页&…

飞牛 fnOS 安装8852be网卡驱动并成功连接

飞牛fnos安装8852be网卡驱动 本人使用的是迷你主机 由于debian内核不识别8852be的网卡&#xff0c;所以需要自行安装网卡驱动 为此搜索了一堆教程 最后折腾过程以及代码如下&#xff0c;建议看完一遍再食用 fnos版本&#xff1a;0.8.36 debian内核版本&#xff1a;6.6.38-tri…

Linux通过docker部署京东矩阵容器服务

获取激活码 将京东无线宝app升级到最新版,然后打开首页,点击号 选择添加容器矩阵,然后获取激活码 运行容器 read -p "请输入你的激活码: " ACTIVECODE;read -p "请输入宿主机的缓存路径: " src;docker rm -f cmatrix;docker run -d -it --name cmatrix …

SQL基础、函数、约束(MySQL第二期)

p.s.这是萌新自己自学总结的笔记&#xff0c;如果想学习得更透彻的话还是请去看大佬的讲解 目录 SQL通用语法SQL数据类型SQL语句分类DDL数据库操作表操作-查询&创建典例表操作-修改字段表操作-改名&删除 DMLDML-插入(添加)数据DML-更新(修改)数据DML-删除数据 DQL基本…

速通 AI+Web3 开发技能: 免费课程+前沿洞察

AI 正以前所未有的速度重塑各行各业&#xff0c;从生成式模型到大规模数据处理&#xff0c;AI 逐渐成为核心驱动力。与此同时&#xff0c;Web3 去中心化技术也在重新定义信任、交易和协作方式。当这两大前沿技术相遇&#xff0c;AI Web3 的融合已不再是理论&#xff0c;而是未…

国产编辑器EverEdit - 输出窗口

1 输出窗口 1.1 应用场景 输出窗口可以显示用户执行某些操作的结果&#xff0c;主要包括&#xff1a; 查找类&#xff1a;查找全部&#xff0c;筛选等待操作&#xff0c;可以把查找结果打印到输出窗口中&#xff1b; 程序类&#xff1a;在执行外部程序时(如&#xff1a;命令窗…

硬件学习笔记--35 AD23的使用常规操作

原理图设计 1&#xff09;新建原理图&#xff0c;File-new-Schematic。相关设置参考&#xff0c;主要包含图纸设置以及常规的工具栏。 PCB的设计 新建PCB&#xff0c;设置相应的规则&#xff08;与原理图中相对应&#xff09;&#xff0c;放到同一个工程中。如果有上一版本的…

2025美赛MCM数学建模A题:《石头台阶的“记忆”:如何用数学揭开历史的足迹》(全网最全思路+模型)

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ 《石头台阶的“记忆”&#xff1a;如何用数学揭开历史的足迹》 目录 《石头台阶的“记忆”&#xff1a;如何用数学揭开历史的足迹》 ✨摘要✨ ✨引言✨ 1. 引言的结构 2. 撰写步骤 &#xff08;1&#xff09;研究背景 &#…

MongoDB 备份与恢复综述

目录 一、基本概述 二、逻辑备份 1、全量备份 2、增量备份 3、恢复 三、物理备份 1、cp/tar/fsync 2、WiredTiger 热备份 3、恢复 四、快照备份 一、基本概述 MongoDB 是一种流行的 NoSQL 数据库&#xff0c;它使用文档存储数据&#xff0c;支持丰富的查询语言和索引…

StarRocks BE源码编译、CLion高亮跳转方法

阅读SR BE源码时&#xff0c;很多类的引用位置爆红找不到&#xff0c;或无法跳转过去&#xff0c;而自己的Linux机器往往缺乏各种C依赖库&#xff0c;配置安装比较麻烦&#xff0c;因此总体的思路是通过CLion远程连接SR社区已经安装完各种依赖库的Docker容器&#xff0c;进行编…

[RoarCTF 2019]Easy Calc1

题目 查看页面源代码 <script>$(#calc).submit(function(){$.ajax({url:"calc.php?num"encodeURIComponent($("#content").val()),type:GET,success:function(data){$("#result").html(<div class"alert alert-success">…

C++异常处理

目录 一、C语言的异常处理方式 二、C异常处理基本概念 三、异常处理的使用 1.异常抛出和捕获的匹配原则 2.异常的重新抛出 3.不建议抛出异常的情况 4.抛出异常规范 四、抛出派生类对象&#xff0c;使用基类捕获 一、C语言的异常处理方式 C语言对于异常处理方式通常为直…

VScode 开发 Springboot 程序

1. 通过maven创建springboot程序 输入 mvn archetype:generate 选择模板&#xff0c;一般默认选择为第 7 种方式&#xff1b; 选择之后&#xff0c;一般要你填写如下内容&#xff1a; groupId: 组织名称&#xff1b;artifactId: 项目名称&#xff1b;version: 版本&#xff0…

12Express简易实战项目(编写api)

12Express简易实战项目 1.初始化1.1 创建项目1.2 配置 cors 跨域1.3配置解析表单数据的中间件1.4 初始化路由相关的文件夹1.5 初始化用户路由模块1.6 抽离用户路由模块中的处理函数 2.登录注册2.1 新建 ev_users 表2.2 安装并配置 mysql 模块2.3 注册(1)实现步骤(2)检测表单数据…

Windows系统Tai时长统计工具的使用体验

Windows系统Tai时长统计工具的使用体验 一、Tai介绍1.1 Tai简介1.2 安装环境要求 二、下载及安装Tai2.1 下载Tai2.2 运行Tai工具 三、Tai的使用体验3.1 系统设置3.2 时长统计3.3 分类管理 四、总结 一、Tai介绍 1.1 Tai简介 Tai是一款专为Windows系统设计的开源软件&#xff…

数据结构——二叉树——堆(1)

今天&#xff0c;我们来写一篇关于数据结构的二叉树的知识。 在学习真正的二叉树之前&#xff0c;我们必不可少的先了解一下二叉树的相关概念。 一&#xff1a;树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层…

Vue入门(Vue基本语法、axios、组件、事件分发)

Vue入门 Vue概述 Vue (读音/vju/&#xff0c;类似于view)是一套用于构建用户界面的渐进式框架&#xff0c;发布于2014年2月。与其它大型框架不同的是&#xff0c;Vue被设计为可以自底向上逐层应用。Vue的核心库只关注视图层&#xff0c;不仅易于上手&#xff0c;还便于与第三…

数据结构:二叉树—面试题(二)

1、二叉树的最近公共祖先 习题链接https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/description/ 描述&#xff1a; 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个节点…