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))

启航团队技术文档