Django+MySQL接口开发完全指南

前言

本文将详细介绍如何使用Django结合MySQL数据库开发RESTful API接口。我们将从环境搭建开始,一步步实现一个完整的接口项目。

环境准备

首先需要安装以下组件:

  • Python 3.8+
  • Django 4.2
  • MySQL 8.0
  • mysqlclient
  • djangorestframework

安装命令

bash 复制代码
# 创建虚拟环境
python -m venv venv
source venv/bin/activate  # Windows使用 venv\Scripts\activate

# 安装依赖
pip install django==4.2
pip install mysqlclient
pip install djangorestframework

项目创建与配置

1. 创建项目

bash 复制代码
django-admin startproject myproject
cd myproject
python manage.py startapp api

2. 配置settings.py

python 复制代码
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',  # 添加rest_framework
    'api',  # 添加api应用
]

# 数据库配置
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'django_demo',
        'USER': 'root',
        'PASSWORD': 'your_password',
        'HOST': '127.0.0.1',
        'PORT': '3306',
    }
}

# REST框架配置
REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 10,
}

数据库模型设计

1. 创建模型(api/models.py)

python 复制代码
from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=100, verbose_name='书名')
    author = models.CharField(max_length=50, verbose_name='作者')
    price = models.DecimalField(max_digits=5, decimal_places=2, verbose_name='价格')
    publish_date = models.DateField(verbose_name='出版日期')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')

    class Meta:
        db_table = 'books'
        verbose_name = '图书'
        verbose_name_plural = verbose_name
        ordering = ['-created_at']

    def __str__(self):
        return self.title

2. 生成并应用数据库迁移

python 复制代码
python manage.py makemigrations
python manage.py migrate

序列化器开发

1. 创建序列化器(api/serializers.py)

python 复制代码
from rest_framework import serializers
from .models import Book

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ['id', 'title', 'author', 'price', 'publish_date', 'created_at', 'updated_at']
        read_only_fields = ['created_at', 'updated_at']

视图开发

1. 创建视图(api/views.py)

python 复制代码
from rest_framework import viewsets, filters
from rest_framework.response import Response
from rest_framework.decorators import action
from django_filters.rest_framework import DjangoFilterBackend
from .models import Book
from .serializers import BookSerializer

class BookViewSet(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filterset_fields = ['author']
    search_fields = ['title', 'author']
    ordering_fields = ['price', 'publish_date']

    @action(detail=False, methods=['get'])
    def get_book_stats(self, request):
        """获取图书统计信息"""
        total_books = Book.objects.count()
        total_authors = Book.objects.values('author').distinct().count()
        avg_price = Book.objects.aggregate(avg_price=models.Avg('price'))

        return Response({
            'total_books': total_books,
            'total_authors': total_authors,
            'average_price': avg_price['avg_price']
        })

URL配置

1. 配置项目URLs(myproject/urls.py)

python 复制代码
from django.contrib import admin
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from api.views import BookViewSet

router = DefaultRouter()
router.register(r'books', BookViewSet)

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include(router.urls)),
]

中间件开发

1. 创建自定义中间件(api/middleware.py)

python 复制代码
import time
from django.utils.deprecation import MiddlewareMixin
import logging

logger = logging.getLogger(__name__)

class RequestLogMiddleware(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
            logger.info(f'{request.method} {request.path} - {response.status_code} - {duration:.2f}s')
        return response

2. 在settings.py中注册中间件

python 复制代码
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',
    'api.middleware.RequestLogMiddleware',  # 添加自定义中间件
]

异常处理

1. 创建自定义异常处理(api/exceptions.py)

python 复制代码
from rest_framework.views import exception_handler
from rest_framework.response import Response
from rest_framework import status

def custom_exception_handler(exc, context):
    response = exception_handler(exc, context)

    if response is None:
        return Response({
            'error': str(exc),
            'message': '服务器内部错误'
        }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    return response

2. 在settings.py中配置异常处理器

python 复制代码
REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'api.exceptions.custom_exception_handler'
}

API接口测试

1. 创建测试用例(api/tests.py)

python 复制代码
from rest_framework.test import APITestCase
from rest_framework import status
from .models import Book
from datetime import date

class BookTests(APITestCase):
    def setUp(self):
        self.book_data = {
            'title': 'Django实战',
            'author': '张三',
            'price': '59.99',
            'publish_date': '2024-01-01'
        }
        self.book = Book.objects.create(**self.book_data)

    def test_create_book(self):
        """测试创建图书"""
        response = self.client.post('/api/books/', self.book_data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(Book.objects.count(), 2)

    def test_get_book_list(self):
        """测试获取图书列表"""
        response = self.client.get('/api/books/')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data['results']), 1)

API接口文档

使用drf-yasg生成Swagger文档:

1. 安装drf-yasg

bash 复制代码
pip install drf-yasg

2. 配置settings.py

python 复制代码
INSTALLED_APPS = [
    ...
    'drf_yasg',
]

3. 配置URLs(myproject/urls.py)

python 复制代码
from django.urls import path, include, re_path
from rest_framework import permissions
from drf_yasg.views import get_schema_view
from drf_yasg import openapi

schema_view = get_schema_view(
   openapi.Info(
      title="图书管理API",
      default_version='v1',
      description="图书管理系统API文档",
      terms_of_service="https://www.yourapp.com/terms/",
      contact=openapi.Contact(email="[email protected]"),
      license=openapi.License(name="BSD License"),
   ),
   public=True,
   permission_classes=(permissions.AllowAny,),
)

urlpatterns = [
    ...
    re_path(r'^swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'),
    path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
    path('redoc/', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
]

接口使用示例

1. 创建图书

bash 复制代码
curl -X POST http://localhost:8000/api/books/ \
     -H "Content-Type: application/json" \
     -d '{"title":"Django实战","author":"张三","price":"59.99","publish_date":"2024-01-01"}'

2. 获取图书列表

python 复制代码
curl http://localhost:8000/api/books/

3. 更新图书

bash 复制代码
curl -X PUT http://localhost:8000/api/books/1/ \
     -H "Content-Type: application/json" \
     -d '{"title":"Django实战(第二版)","author":"张三","price":"69.99","publish_date":"2024-01-01"}'

4. 删除图书

bash 复制代码
curl -X DELETE http://localhost:8000/api/books/1/

性能优化建议

  1. 使用数据库索引

    python 复制代码
    class Book(models.Model):
        ...
        class Meta:
            indexes = [
                models.Index(fields=['title']),
                models.Index(fields=['author']),
            ]
  2. 使用缓存

    python 复制代码
    from django.core.cache import cache
    
    class BookViewSet(viewsets.ModelViewSet):
        def list(self, request):
            cache_key = 'book_list'
            cached_data = cache.get(cache_key)
            
            if cached_data is None:
                queryset = self.filter_queryset(self.get_queryset())
                serializer = self.get_serializer(queryset, many=True)
                cached_data = serializer.data
                cache.set(cache_key, cached_data, timeout=300)  # 缓存5分钟
                
            return Response(cached_data)

总结

本文详细介绍了使用Django开发RESTful API的完整流程,包括:

  1. 环境搭建和项目配置
  2. 数据库模型设计
  3. 序列化器开发
  4. 视图和URL配置
  5. 中间件和异常处理
  6. 测试用例编写
  7. API文档生成
  8. 性能优化建议

通过按照本教程的步骤,你可以快速搭建一个功能完善的Django API项目。建议在实际开发中根据具体需求进行适当调整和扩展。

相关推荐
伤不起bb21 分钟前
MySQL 高可用
linux·运维·数据库·mysql·安全·高可用
shykevin2 小时前
python开发Streamable HTTP MCP应用
开发语言·网络·python·网络协议·http
漫路在线3 小时前
JS逆向-某易云音乐下载器
开发语言·javascript·爬虫·python
成功人chen某6 小时前
配置VScodePython环境Python was not found;
开发语言·python
2301_786964366 小时前
EXCEL Python 实现绘制柱状线型组合图和树状图(包含数据透视表)
python·microsoft·excel
skd89996 小时前
小蜗牛拨号助手用户使用手册
python
「QT(C++)开发工程师」6 小时前
STM32 | FreeRTOS 递归信号量
python·stm32·嵌入式硬件
运维成长记7 小时前
mysql数据库-中间件MyCat
数据库·mysql·中间件
史迪仔01127 小时前
[python] Python单例模式:__new__与线程安全解析
开发语言·python·单例模式
尘客.7 小时前
DataX从Mysql导数据到Hive分区表案例
数据库·hive·mysql