Django REST Framework 构建安卓应用后端API:从开发到部署的完整实战指南

本文将详细介绍如何使用 Django 和 Django REST Framework (DRF) 为安卓应用构建稳定、安全、高效的 RESTful API 接口。


第一阶段:项目基础设置

1.1 安装必要的包

bash 复制代码
pip install django djangorestframework django-cors-headers djangorestframework-simplejwt pillow

1.2 创建Django项目和应用

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

1.3 配置 settings.py

python 复制代码
# settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # 第三方应用
    'rest_framework',
    'rest_framework_simplejwt',
    'corsheaders',
    # 自定义应用
    'api',
]

# DRF 配置
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ),
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',  # 默认需要认证
    ),
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 20
}

# JWT 配置
from datetime import timedelta
SIMPLE_JWT = {
    'ACCESS_TOKEN_LIFETIME': timedelta(days=1),
    'REFRESH_TOKEN_LIFETIME': timedelta(days=7),
}

# CORS 配置(允许安卓应用访问)
CORS_ALLOWED_ORIGINS = [
    "http://localhost:8080",        # 开发时安卓模拟器
    "http://192.168.1.100:8080",    # 本地网络地址
    "https://yourdomain.com",       # 生产域名
]

CORS_ALLOW_CREDENTIALS = True

# 允许所有域名访问(开发阶段,生产环境应限制)
# CORS_ALLOW_ALL_ORIGINS = True

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',  # 尽量放在最前
    'django.middleware.security.SecurityMiddleware',
    # ... 其他中间件
]

第二阶段:数据模型设计

2.1 定义核心模型(api/models.py)

python 复制代码
from django.db import models
from django.contrib.auth.models import User

class Category(models.Model):
    name = models.CharField(max_length=100)
    description = models.TextField(blank=True)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.name

class Product(models.Model):
    name = models.CharField(max_length=200)
    description = models.TextField()
    price = models.DecimalField(max_digits=10, decimal_places=2)
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    image = models.ImageField(upload_to='products/', null=True, blank=True)
    stock = models.IntegerField(default=0)
    is_active = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.name

class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    phone = models.CharField(max_length=15, blank=True)
    avatar = models.ImageField(upload_to='avatars/', null=True, blank=True)
    address = models.TextField(blank=True)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.user.username

class Order(models.Model):
    STATUS_CHOICES = [
        ('pending', '待处理'),
        ('processing', '处理中'),
        ('shipped', '已发货'),
        ('delivered', '已送达'),
        ('cancelled', '已取消'),
    ]

    user = models.ForeignKey(User, on_delete=models.CASCADE)
    total_amount = models.DecimalField(max_digits=10, decimal_places=2)
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending')
    shipping_address = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

class OrderItem(models.Model):
    order = models.ForeignKey(Order, on_delete=models.CASCADE)
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    quantity = models.IntegerField()
    price = models.DecimalField(max_digits=10, decimal_places=2)

2.2 执行数据库迁移

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

第三阶段:序列化器创建

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

python 复制代码
from rest_framework import serializers
from django.contrib.auth.models import User
from .models import Category, Product, UserProfile, Order, OrderItem

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('id', 'username', 'email', 'first_name', 'last_name')

class UserProfileSerializer(serializers.ModelSerializer):
    user = UserSerializer(read_only=True)
    
    class Meta:
        model = UserProfile
        fields = '__all__'

class CategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = Category
        fields = '__all__'

class ProductSerializer(serializers.ModelSerializer):
    category_name = serializers.CharField(source='category.name', read_only=True)
    
    class Meta:
        model = Product
        fields = ('id', 'name', 'description', 'price', 'category', 
                 'category_name', 'image', 'stock', 'is_active', 'created_at')

class OrderItemSerializer(serializers.ModelSerializer):
    product_name = serializers.CharField(source='product.name', read_only=True)
    
    class Meta:
        model = OrderItem
        fields = ('id', 'product', 'product_name', 'quantity', 'price')

class OrderSerializer(serializers.ModelSerializer):
    items = OrderItemSerializer(many=True, read_only=True)
    user_info = UserSerializer(source='user', read_only=True)
    
    class Meta:
        model = Order
        fields = ('id', 'user', 'user_info', 'total_amount', 'status', 
                 'shipping_address', 'items', 'created_at', 'updated_at')

第四阶段:视图和API端点

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

python 复制代码
from rest_framework import viewsets, status, permissions
from rest_framework.decorators import action
from rest_framework.response import Response
from django.contrib.auth.models import User
from .models import Category, Product, UserProfile, Order, OrderItem
from .serializers import (UserSerializer, UserProfileSerializer, 
                         CategorySerializer, ProductSerializer, 
                         OrderSerializer, OrderItemSerializer)

class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = [permissions.IsAdminUser]  # 只有管理员可以管理用户

class UserProfileViewSet(viewsets.ModelViewSet):
    queryset = UserProfile.objects.all()
    serializer_class = UserProfileSerializer

    def get_queryset(self):
        # 用户只能访问自己的资料
        if self.request.user.is_staff:
            return UserProfile.objects.all()
        return UserProfile.objects.filter(user=self.request.user)

class CategoryViewSet(viewsets.ModelViewSet):
    queryset = Category.objects.all()
    serializer_class = CategorySerializer
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]  # 读不需要认证

class ProductViewSet(viewsets.ModelViewSet):
    queryset = Product.objects.filter(is_active=True)
    serializer_class = ProductSerializer

    @action(detail=False, methods=['get'])
    def by_category(self, request):
        category_id = request.query_params.get('category')
        products = Product.objects.filter(category_id=category_id, is_active=True)
        serializer = self.get_serializer(products, many=True)
        return Response(serializer.data)

class OrderViewSet(viewsets.ModelViewSet):
    serializer_class = OrderSerializer

    def get_queryset(self):
        # 用户只能查看自己的订单,管理员可以查看所有
        if self.request.user.is_staff:
            return Order.objects.all()
        return Order.objects.filter(user=self.request.user)

    def perform_create(self, serializer):
        # 自动设置当前用户为订单所有者
        serializer.save(user=self.request.user)

class AuthViewSet(viewsets.ViewSet):
    """认证相关接口"""
    
    @action(detail=False, methods=['post'], permission_classes=[permissions.AllowAny])
    def register(self, request):
        # 用户注册逻辑
        serializer = UserSerializer(data=request.data)
        if serializer.is_valid():
            user = User.objects.create_user(
                username=request.data['username'],
                email=request.data.get('email', ''),
                password=request.data['password']
            )
            # 创建用户资料
            UserProfile.objects.create(user=user)
            return Response({'message': '用户注册成功'}, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

第五阶段:路由配置

5.1 配置URL路由(api/urls.py)

python 复制代码
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
from .views import (UserViewSet, UserProfileViewSet, CategoryViewSet, 
                   ProductViewSet, OrderViewSet, AuthViewSet)

router = DefaultRouter()
router.register(r'users', UserViewSet)
router.register(r'profiles', UserProfileViewSet)
router.register(r'categories', CategoryViewSet)
router.register(r'products', ProductViewSet)
router.register(r'orders', OrderViewSet)
router.register(r'auth', AuthViewSet, basename='auth')

urlpatterns = [
    path('', include(router.urls)),
    path('token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
]

5.2 主项目路由配置(backend/urls.py)

python 复制代码
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include('api.urls')),  # API路由
]

# 开发环境提供媒体文件服务
if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

第六阶段:安卓端接口调用示例

6.1 登录获取Token

kotlin 复制代码
// Kotlin 示例代码
interface ApiService {
    @POST("api/token/")
    suspend fun login(@Body request: LoginRequest): TokenResponse
    
    @POST("api/auth/register/")
    suspend fun register(@Body request: RegisterRequest): Response<MessageResponse>
}

data class LoginRequest(val username: String, val password: String)
data class TokenResponse(val access: String, val refresh: String)
data class RegisterRequest(val username: String, val email: String, val password: String)
data class MessageResponse(val message: String)

6.2 获取商品列表

kotlin 复制代码
@GET("api/products/")
suspend fun getProducts(
    @Header("Authorization") token: String,
    @Query("page") page: Int = 1
): Response<ProductListResponse>

@GET("api/products/by_category/")
suspend fun getProductsByCategory(
    @Header("Authorization") token: String,
    @Query("category") categoryId: Int
): Response<List<ProductResponse>>

6.3 创建订单

kotlin 复制代码
@POST("api/orders/")
suspend fun createOrder(
    @Header("Authorization") token: String,
    @Body request: CreateOrderRequest
): Response<OrderResponse>

第七阶段:生产环境部署配置

7.1 安全配置(settings.py

python 复制代码
# 生产环境设置
DEBUG = False

# 允许的域名
ALLOWED_HOSTS = ['yourdomain.com', 'api.yourdomain.com']

# CORS 白名单
CORS_ALLOWED_ORIGINS = [
    "https://yourapp.android.com",
    "https://yourdomain.com",
]

# 数据库配置
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'mydatabase',
        'USER': 'myuser',
        'PASSWORD': 'mypassword',
        'HOST': 'localhost',
        'PORT': '5432',
    }
}

# 静态文件和媒体文件配置
STATIC_URL = '/static/'
STATIC_ROOT = '/var/www/backend/static/'
MEDIA_URL = '/media/'
MEDIA_ROOT = '/var/www/backend/media/'

7.2 添加限流和缓存

python 复制代码
REST_FRAMEWORK = {
    # ... 其他配置
    'DEFAULT_THROTTLE_CLASSES': [
        'rest_framework.throttling.AnonRateThrottle',
        'rest_framework.throttling.UserRateThrottle'
    ],
    'DEFAULT_THROTTLE_RATES': {
        'anon': '100/day',  # 匿名用户100次/天
        'user': '1000/day'  # 认证用户1000次/天
    },
    'DEFAULT_CACHE_RESPONSE_TIMEOUT': 300  # 5分钟缓存
}

第八阶段:API文档和测试

8.1 安装DRF Spectacular用于API文档

bash 复制代码
pip install drf-spectacular

8.2 配置API文档

python 复制代码
# settings.py
INSTALLED_APPS = [
    # ...
    'drf_spectacular',
]

REST_FRAMEWORK = {
    # ...
    'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
}

SPECTACULAR_SETTINGS = {
    'TITLE': '安卓APP API',
    'DESCRIPTION': '为安卓应用提供的RESTful API接口',
    'VERSION': '1.0.0',
}

8.3 添加文档路由

python 复制代码
# urls.py
from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView, SpectacularSwaggerView

urlpatterns = [
    # ...
    path('api/schema/', SpectacularAPIView.as_view(), name='schema'),
    path('api/docs/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
    path('api/redoc/', SpectacularRedocView.as_view(url_name='schema'), name='redoc'),
]

完整的功能特性

✅ 用户系统: 注册、登录、JWT认证、用户资料管理

✅ 商品管理: 分类、商品列表、搜索、详情

✅ 订单系统: 创建订单、订单状态管理、历史订单

✅ 权限控制: 用户权限、管理员权限

✅ 文件上传: 用户头像、商品图片

✅ 分页和过滤: 大数据量分页显示

✅ API文档: 自动生成的交互式文档

✅ 安全机制: CORS、限流、SQL注入防护

✅ 错误处理: 统一的错误响应格式

这个完整的API后端可以为安卓应用提供所有必要的接口服务,具有良好的扩展性和安全性。

相关推荐
Dfreedom.2 小时前
在Windows上搭建GPU版本PyTorch运行环境的详细步骤
c++·人工智能·pytorch·python·深度学习
会豪2 小时前
工业仿真(simulation)-- 自定义物流路线(5)
后端
爱读源码的大都督2 小时前
挑战一下,用Java手写Transformer,先手写QKV,能成功吗?
java·后端·程序员
华仔啊3 小时前
面试官灵魂拷问:count(1)、count(*)、count(列)到底差在哪?MySQL 性能翻车现场
java·后端
huangyuchi.3 小时前
【Linux系统】初见线程,概念与控制
linux·运维·服务器·页表·linux线程概念·linux线程控制·分页式存储管理
葡萄城技术团队3 小时前
SpreadJS:让多源数据筛选排序如 Excel 般便捷高效
运维·服务器·excel
三十_3 小时前
【Docker】学习 Docker 的过程中,我是这样把镜像越做越小的
前端·后端·docker
一只拉古3 小时前
C# 代码审查面试准备:实用示例与技巧
后端·面试·架构
_新一3 小时前
Go Map源码解析
后端