Django 博客系统开发教程

1. Django 简介和特性

Django 是一个高级的 Python Web 框架,它鼓励快速开发和干净、实用的设计。Django 遵循 MVT(Model-View-Template)架构,提供了许多内置功能,如用户认证、内容管理、表单处理、文件上传等。

主要特性

  • ORM(对象关系映射):简化数据库操作。
  • 自动管理界面:快速生成管理后台。
  • URL 路由:灵活的 URL 设计。
  • 模板系统:强大的模板引擎。
  • 表单处理:简化表单创建和验证。
  • 安全性:内置多种安全机制。

2. 安装和环境设置

安装 Python

确保你的系统上安装了 Python 3.x。你可以通过以下命令检查:

python --version

安装 Django

使用 pip 安装 Django:

pip install django

创建虚拟环境

建议使用虚拟环境来隔离项目依赖:

python -m venv myenv
source myenv/bin/activate  # 在 Windows 上使用 `myenv\Scripts\activate`

3. 项目结构和管理命令

创建 Django 项目

使用以下命令创建一个新的 Django 项目:

django-admin startproject myblog

项目结构

myblog/
    manage.py
    myblog/
        __init__.py
        settings.py
        urls.py
        asgi.py
        wsgi.py

管理命令

  • 运行开发服务器:
    python manage.py runserver
    
  • 创建应用:
    python manage.py startapp blog
    

4. MVT 架构

Model

模型是数据的唯一和明确的来源。它包含数据的基本字段和行为。

View

视图是处理请求并返回响应的逻辑。它可以是函数或类。

Template

模板是定义用户界面外观的文件。Django 使用模板语言来动态生成 HTML。

5. 第一个 Django 应用

创建应用

python manage.py startapp blog

定义模型

在 blog/models.py 中定义一个简单的模型:

from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    pub_date = models.DateTimeField('date published')

注册模型

在 blog/admin.py 中注册模型:

from django.contrib import admin
from .models import Post

admin.site.register(Post)

创建和应用迁移

python manage.py makemigrations
python manage.py migrate

6. 模型定义和字段类型

常用字段类型

  • CharField:用于短字符串。
  • TextField:用于长文本。
  • IntegerField:用于整数。
  • DateTimeField:用于日期和时间。
  • ForeignKey:用于一对多关系。
  • ManyToManyField:用于多对多关系。

示例

class Author(models.Model):
    name = models.CharField(max_length=100)
    email = models.EmailField()

class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.ForeignKey(Author, on_delete=models.CASCADE)
    pub_date = models.DateField()

7. 数据库迁移

创建迁移

python manage.py makemigrations

应用迁移

python manage.py migrate

8. 查询集和管理器

查询集

查询集是从数据库中获取对象的集合。你可以使用过滤器、排序等操作。

示例

posts = Post.objects.filter(pub_date__year=2023)

管理器

管理器是 Django 模型用于数据库查询的接口。默认管理器是 objects。

9. 模型关系

一对多关系

使用 ForeignKey 字段:

class Author(models.Model):
    name = models.CharField(max_length=100)

class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.ForeignKey(Author, on_delete=models.CASCADE)

多对多关系

使用 ManyToManyField 字段:

class Publication(models.Model):
    title = models.CharField(max_length=30)

class Article(models.Model):
    headline = models.CharField(max_length=100)
    publications = models.ManyToManyField(Publication)

10. 自定义模型方法

示例

class Post(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    pub_date = models.DateTimeField('date published')

    def __str__(self):
        return self.title

    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

11. 函数视图和类视图

函数视图

from django.http import HttpResponse

def index(request):
    return HttpResponse("Hello, world!")

类视图

from django.views import View
from django.http import HttpResponse

class IndexView(View):
    def get(self, request):
        return HttpResponse("Hello, world!")

12. URL 模式和命名

URL 模式

在 urls.py 中定义 URL 模式:

from django.urls import path
from . import views

urlpatterns = [
    path('', views.index, name='index'),
]

命名 URL

<a href="{% url 'index' %}">Home</a>

13. 视图参数和请求处理

视图参数

def detail(request, post_id):
    return HttpResponse(f"Post ID: {post_id}")

请求处理

def create_post(request):
    if request.method == 'POST':
        # 处理 POST 请求
        pass
    else:
        # 处理 GET 请求
        pass

14. 通用视图

示例

from django.views.generic import ListView, DetailView
from .models import Post

class PostListView(ListView):
    model = Post
    template_name = 'blog/post_list.html'

class PostDetailView(DetailView):
    model = Post
    template_name = 'blog/post_detail.html'

15. 中间件

自定义中间件

class MyMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # 请求前的处理
        response = self.get_response(request)
        # 响应后的处理
        return response

16. 模板语法和标签

模板语法

<h1>{{ post.title }}</h1>
<p>{{ post.content }}</p>

模板标签

{% if user.is_authenticated %}
    <p>Welcome, {{ user.username }}</p>
{% else %}
    <p>Please log in.</p>
{% endif %}

17. 模板继承

基础模板

<!-- base.html -->
<!DOCTYPE html>
<html>
<head>
    <title>{% block title %}My Blog{% endblock %}</title>
</head>
<body>
    <header>
        <h1>My Blog</h1>
    </header>
    <main>
        {% block content %}{% endblock %}
    </main>
</body>
</html>

子模板

<!-- post_detail.html -->
{% extends "base.html" %}

{% block title %}{{ post.title }}{% endblock %}

{% block content %}
    <h1>{{ post.title }}</h1>
    <p>{{ post.content }}</p>
{% endblock %}

18. 上下文处理器

自定义上下文处理器

def my_context_processor(request):
    return {'foo': 'bar'}

注册上下文处理器

在 settings.py 中:

TEMPLATES = [
    {
        'OPTIONS': {
            'context_processors': [
                'myapp.context_processors.my_context_processor',
            ],
        },
    },
]

19. 自定义模板标签和过滤器

自定义过滤器

from django import template

register = template.Library()

@register.filter
def lower_case(value):
    return value.lower()

使用过滤器

{{ post.title|lower_case }}

20. 静态文件处理

配置静态文件

在 settings.py 中:

STATIC_URL = '/static/'
STATICFILES_DIRS = [
    BASE_DIR / "static",
]

使用静态文件

{% load static %}
<img src="{% static 'images/logo.png' %}" alt="Logo">

21. Django Form 类

创建表单

from django import forms

class ContactForm(forms.Form):
    name = forms.CharField(max_length=100)
    email = forms.EmailField()
    message = forms.CharField(widget=forms.Textarea)

使用表单

def contact(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            # 处理表单数据
            pass
    else:
        form = ContactForm()
    return render(request, 'contact.html', {'form': form})

22. 表单验证

自定义验证

from django import forms

class ContactForm(forms.Form):
    name = forms.CharField(max_length=100)
    email = forms.EmailField()
    message = forms.CharField(widget=forms.Textarea)

    def clean_email(self):
        email = self.cleaned_data['email']
        if not email.endswith('@example.com'):
            raise forms.ValidationError("Only example.com emails are allowed.")
        return email

23. ModelForm

创建 ModelForm

from django import forms
from .models import Post

class PostForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = ['title', 'content', 'pub_date']

使用 ModelForm

def create_post(request):
    if request.method == 'POST':
        form = PostForm(request.POST)
        if form.is_valid():
            form.save()
    else:
        form = PostForm()
    return render(request, 'create_post.html', {'form': form})

24. 表单集 (Formsets)

创建表单集

from django.forms import formset_factory
from .forms import ContactForm

ContactFormSet = formset_factory(ContactForm, extra=2)

使用表单集

def contact_formset(request):
    if request.method == 'POST':
        formset = ContactFormSet(request.POST)
        if formset.is_valid():
            for form in formset:
                # 处理每个表单
                pass
    else:
        formset = ContactFormSet()
    return render(request, 'contact_formset.html', {'formset': formset})

25. 文件上传处理

配置文件上传

在 settings.py 中:

MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'

创建表单

from django import forms

class UploadFileForm(forms.Form):
    title = forms.CharField(max_length=50)
    file = forms.FileField()

处理文件上传

def upload_file(request):
    if request.method == 'POST':
        form = UploadFileForm(request.POST, request.FILES)
        if form.is_valid():
            handle_uploaded_file(request.FILES['file'])
    else:
        form = UploadFileForm()
    return render(request, 'upload.html', {'form': form})

26. 用户认证系统

内置认证视图

from django.contrib.auth import views as auth_views

urlpatterns = [
    path('login/', auth_views.LoginView.as_view(), name='login'),
    path('logout/', auth_views.LogoutView.as_view(), name='logout'),
]

自定义用户模型

from django.contrib.auth.models import AbstractUser

class CustomUser(AbstractUser):
    bio = models.TextField(max_length=500, blank=True)

27. 权限和组

创建权限

from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
from .models import Post

content_type = ContentType.objects.get_for_model(Post)
permission = Permission.objects.create(
    codename='can_publish',
    name='Can Publish Posts',
    content_type=content_type,
)

分配权限

user.user_permissions.add(permission)

28. 登录、注销和注册视图

登录视图

from django.contrib.auth import views as auth_views

urlpatterns = [
    path('login/', auth_views.LoginView.as_view(template_name='login.html'), name='login'),
]

注销视图

urlpatterns = [
    path('logout/', auth_views.LogoutView.as_view(), name='logout'),
]

注册视图

from django.contrib.auth.forms import UserCreationForm
from django.urls import reverse_lazy
from django.views import generic

class SignUpView(generic.CreateView):
    form_class = UserCreationForm
    success_url = reverse_lazy('login')
    template_name = 'signup.html'

29. 基于类的权限控制

类视图权限控制

from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import DetailView
from .models import Post

class PostDetailView(LoginRequiredMixin, DetailView):
    model = Post
    template_name = 'post_detail.html'

30. Admin 站点定制

自定义 Admin 操作

from django.contrib import admin
from .models import Post

@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
    list_display = ('title', 'pub_date', 'was_published_recently')

    def make_published(self, request, queryset):
        queryset.update(status='p')
    make_published.short_description = "Mark selected posts as published"

31. 模型注册和配置

注册模型

from django.contrib import admin
from .models import Post

admin.site.register(Post)

配置模型

@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
    list_display = ('title', 'pub_date')
    list_filter = ('pub_date',)
    search_fields = ('title', 'content')

32. 自定义 Admin 操作

自定义操作

from django.contrib import admin
from .models import Post

@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
    actions = ['make_published']