Skip to content

Python Web 开发指南 ​

目录 ​

Web 框架 ​

Django ​

python
from django.shortcuts import render, redirect
from django.views.generic import ListView, DetailView, CreateView, UpdateView
from .models import User
from .forms import UserForm

class UserListView(ListView):
    model = User
    template_name = 'users/list.html'
    context_object_name = 'users'

class UserDetailView(DetailView):
    model = User
    template_name = 'users/detail.html'
    context_object_name = 'user'

class UserCreateView(CreateView):
    model = User
    form_class = UserForm
    template_name = 'users/form.html'
    success_url = '/users/'

class UserUpdateView(UpdateView):
    model = User
    form_class = UserForm
    template_name = 'users/form.html'
    success_url = '/users/'

Flask ​

python
from flask import Flask, render_template, request, redirect, url_for
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
db = SQLAlchemy(app)

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80), nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)

@app.route('/users')
def list_users():
    users = User.query.all()
    return render_template('users/list.html', users=users)

@app.route('/users/<int:id>')
def get_user(id):
    user = User.query.get_or_404(id)
    return render_template('users/detail.html', user=user)

@app.route('/users/new', methods=['GET', 'POST'])
def create_user():
    if request.method == 'POST':
        user = User(
            name=request.form['name'],
            email=request.form['email']
        )
        db.session.add(user)
        db.session.commit()
        return redirect(url_for('list_users'))
    return render_template('users/form.html')

模板引擎 ​

Jinja2 模板 ​

html
<!DOCTYPE html>
<html>
<head>
    <title>用户列表</title>
</head>
<body>
    <h1>用户列表</h1>
    <table>
        <thead>
            <tr>
                <th>ID</th>
                <th>姓名</th>
                <th>邮箱</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            {% for user in users %}
            <tr>
                <td>{{ user.id }}</td>
                <td>{{ user.name }}</td>
                <td>{{ user.email }}</td>
                <td>
                    <a href="{{ url_for('get_user', id=user.id) }}">查看</a>
                    <a href="{{ url_for('edit_user', id=user.id) }}">编辑</a>
                </td>
            </tr>
            {% endfor %}
        </tbody>
    </table>
</body>
</html>

静态文件 ​

静态文件处理 ​

python
# Django
STATIC_URL = '/static/'
STATICFILES_DIRS = [
    BASE_DIR / "static",
]

# Flask
app = Flask(__name__, static_folder='static')

会话管理 ​

Django 会话 ​

python
from django.contrib.sessions.backends.db import SessionStore

def login(request):
    if request.method == 'POST':
        user = authenticate(
            username=request.POST['username'],
            password=request.POST['password']
        )
        if user is not None:
            login(request, user)
            request.session['user_id'] = user.id
            return redirect('home')
    return render(request, 'login.html')

def logout(request):
    logout(request)
    request.session.flush()
    return redirect('login')

Flask 会话 ​

python
from flask import session

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        user = User.query.filter_by(
            username=request.form['username']
        ).first()
        if user and check_password_hash(user.password, request.form['password']):
            session['user_id'] = user.id
            return redirect(url_for('home'))
    return render_template('login.html')

@app.route('/logout')
def logout():
    session.pop('user_id', None)
    return redirect(url_for('login'))

表单处理 ​

Django 表单 ​

python
from django import forms

class UserForm(forms.ModelForm):
    class Meta:
        model = User
        fields = ['name', 'email', 'password']
        widgets = {
            'password': forms.PasswordInput()
        }

    def clean_email(self):
        email = self.cleaned_data.get('email')
        if User.objects.filter(email=email).exists():
            raise forms.ValidationError('该邮箱已被注册')
        return email

Flask 表单 ​

python
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField
from wtforms.validators import DataRequired, Email, Length

class UserForm(FlaskForm):
    name = StringField('姓名', validators=[DataRequired()])
    email = StringField('邮箱', validators=[DataRequired(), Email()])
    password = PasswordField('密码', validators=[
        DataRequired(),
        Length(min=6, message='密码长度不能小于6位')
    ])

文件上传 ​

Django 文件上传 ​

python
from django.core.files.storage import FileSystemStorage

def upload_file(request):
    if request.method == 'POST' and request.FILES['file']:
        file = request.FILES['file']
        fs = FileSystemStorage()
        filename = fs.save(file.name, file)
        uploaded_file_url = fs.url(filename)
        return render(request, 'upload.html', {
            'uploaded_file_url': uploaded_file_url
        })
    return render(request, 'upload.html')

Flask 文件上传 ​

python
import os
from werkzeug.utils import secure_filename

UPLOAD_FOLDER = 'uploads'
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'}

app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER

def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

@app.route('/upload', methods=['POST'])
def upload_file():
    if 'file' not in request.files:
        return redirect(request.url)
    file = request.files['file']
    if file.filename == '':
        return redirect(request.url)
    if file and allowed_file(file.filename):
        filename = secure_filename(file.filename)
        file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
        return redirect(url_for('uploaded_file', filename=filename))

前端集成 ​

集成 Vue.js ​

html
<!DOCTYPE html>
<html>
<head>
    <title>用户管理</title>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
    <div id="app">
        <h1>用户列表</h1>
        <table>
            <thead>
                <tr>
                    <th>ID</th>
                    <th>姓名</th>
                    <th>邮箱</th>
                    <th>操作</th>
                </tr>
            </thead>
            <tbody>
                <tr v-for="user in users">
                    <td>{{ user.id }}</td>
                    <td>{{ user.name }}</td>
                    <td>{{ user.email }}</td>
                    <td>
                        <button @click="editUser(user)">编辑</button>
                        <button @click="deleteUser(user.id)">删除</button>
                    </td>
                </tr>
            </tbody>
        </table>
    </div>
    
    <script>
        new Vue({
            el: '#app',
            data: {
                users: []
            },
            mounted() {
                this.loadUsers();
            },
            methods: {
                loadUsers() {
                    axios.get('/api/users')
                        .then(response => {
                            this.users = response.data;
                        });
                },
                editUser(user) {
                    // 处理编辑
                },
                deleteUser(id) {
                    axios.delete(`/api/users/${id}`)
                        .then(() => {
                            this.loadUsers();
                        });
                }
            }
        });
    </script>
</body>
</html>

性能优化 ​

缓存控制 ​

python
# Django
from django.views.decorators.cache import cache_control

@cache_control(max_age=31536000)
def static_file(request, path):
    return serve(request, path)

# Flask
@app.after_request
def add_header(response):
    response.headers['Cache-Control'] = 'public, max-age=31536000'
    return response

压缩 ​

python
# Django
MIDDLEWARE = [
    'django.middleware.gzip.GZipMiddleware',
]

# Flask
from flask_compress import Compress

compress = Compress()
compress.init_app(app)

安全实践 ​

CSRF 保护 ​

python
# Django
MIDDLEWARE = [
    'django.middleware.csrf.CsrfViewMiddleware',
]

# Flask
from flask_wtf.csrf import CSRFProtect

csrf = CSRFProtect()
csrf.init_app(app)

XSS 防护 ​

python
# Django
from django.utils.html import escape

def user_profile(request, username):
    user = get_object_or_404(User, username=username)
    return render(request, 'profile.html', {
        'username': escape(user.username)
    })

# Flask
from markupsafe import escape

@app.route('/user/<username>')
def user_profile(username):
    return render_template('profile.html', username=escape(username))

启航团队技术文档