嘿,Django的小伙伴们,今天咱们来聊点实在的,能让你下班早走半小时的干货——如何优雅地包装你的API视图。
你是不是也写过这样的代码?
from django.http import JsonResponse
def my_old_api(request):
if request.method != 'POST':
return JsonResponse({'error': 'Method not allowed'}, status=405)
try:
data = json.loads(request.body)
name = data['name']
# ... 一堆业务逻辑
return JsonResponse({'msg': f'Hello, {name}!'})
except json.JSONDecodeError:
return JsonResponse({'error': 'Invalid JSON'}, status=400)
except KeyError:
return JsonResponse({'error': 'Missing name'}, status=400)
看着就心累,对不对?像极了在菜市场跟人讨价还价,得不停地检查这个、验证那个,稍微不注意就报错。这代码,写得憋屈,看得流泪。
别慌!今天我给你请来一位“包装大师”——Django REST framework。它能让你的API视图从“路边摊”升级到“米其林三星”,不仅代码清爽,功能还贼拉强大!
第一式:神功入门,@api_view装饰器
这位“大师”带来的第一件神器,叫做 @api_view 装饰器。你可别小看这个“@”符号,它就像给你的视图函数穿上了一件“黄金圣衣”。
它主要干了三件大事:
- 限制HTTP方法:你明确告诉它:“哥们儿,我这个视图只接待GET和POST两位客人。” 它就会帮你把其他想闯进来的(比如PUT, DELETE)统统拦在门外,并自动返回一个漂亮的
405 Method Not Allowed错误,都不用你动手! - 智能解析请求:你再也不需要手动
json.loads(request.body)了!DRF的Request对象会把传过来的数据(无论是JSON、表单数据还是其他格式)自动解析好,放到request.data这个“魔法字典”里。直接用就行,爽歪歪! - 智能渲染响应:你也不再需要手动
JsonResponse()了!你只需要返回普通的Python字典或列表,DRF的Response对象会自动帮你把它转换成客户端想要的格式(比如JSON)。
光说不练假把式,咱们直接上代码,开一家“虚拟烧烤店”吧!
场景: 我们要创建一个API,用来“点烤串”。可以查看菜单(GET),也可以下单(POST)。
第一步:安装并配置DRF
pip install djangorestframework
在你的settings.py里,把它加到INSTALLED_APPS中:
INSTALLED_APPS = [
# ... 其他应用
'rest_framework',
]
第二步:编写我们“包装”过的视图
在views.py里:
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status
# 我们的“菜单”数据库(先临时用个列表代替)
menu = [
{'id': 1, 'name': '羊肉串', 'price': 5},
{'id': 2, 'name': '烤韭菜', 'price': 3},
{'id': 3, 'name': '大腰子', 'price': 15},
]
orders = [] # 用来存订单
# 看!神奇的@api_view装饰器登场了!
@api_view(['GET', 'POST'])
def korean_barbecue(request):
"""
烧烤店API:GET看菜单,POST下单。
"""
# 1. 如果是客人想查看菜单(GET请求)
if request.method == 'GET':
# 直接返回菜单数据,Response会自动转成JSON
return Response({'menu': menu, 'message': '欢迎光临老王烧烤!'})
# 2. 如果是客人下单(POST请求)
elif request.method == 'POST':
# 看!这里直接用了request.data,就像用普通的字典一样!
item_name = request.data.get('item')
# 数据验证(简单的)
if not item_name:
return Response({'error': '哥们,你还没说要点啥呢!'}, status=status.HTTP_400_BAD_REQUEST)
# 找一下点的菜在不在菜单上
ordered_item = next((item for item in menu if item['name'] == item_name), None)
if not ordered_item:
return Response({'error': '抱歉,本店没有这个菜。'}, status=status.HTTP_404_NOT_FOUND)
# 记录订单
order_id = len(orders) + 1
new_order = {'order_id': order_id, 'item': ordered_item}
orders.append(new_order)
# 返回下单成功的信息!
return Response({
'message': f'菜已下单!您点的{ordered_item["name"]}正在火上烤着,订单号是{order_id}。'
}, status=status.HTTP_201_CREATED)
配置一下URL(urls.py):
from django.urls import path
from . import views
urlpatterns = [
path('api/bbq/', views.korean_barbecue, name='bbq-api'),
]
现在,让我们来“品尝”一下这个API!
运行服务器,用浏览器访问 http://127.0.0.1:8000/api/bbq/。
哇哦! 你看到了什么?不是一个干巴巴的JSON,而是一个DRF自带的可视化API界面!你可以在这个页面上直接点击进行POST操作,这就是“包装”带来的额外福利!
你用Postman或者curl测试一下POST请求:
curl -X POST http://127.0.0.1:8000/api/bbq/ -H "Content-Type: application/json" -d '{"item": "羊肉串"}'
你会收到一个优雅的响应:
{
"message": "菜已下单!您点的羊肉串正在火上烤着,订单号是1。"
}
怎么样?是不是感觉代码瞬间清爽了,功能反而更强大了?这就是“包装”的力量!
第二式:进阶高手,APIView类
如果你的视图逻辑更复杂,比如要处理增删改查(CRUD)一整套,那么@api_view可能就显得有点“小家子气”了。这时候,就该**APIView**类闪亮登场!
APIView是基于类的视图(CBV),它能把不同的HTTP方法清晰地分离到不同的类方法中,结构更清晰,也更利于复用。
来,我们把刚才的烧烤店用APIView重写一遍:
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
class BarbecueAPIView(APIView):
"""
用类视图实现的烧烤店API
"""
# 初始化“数据库”
def __init__(self):
self.menu = [...]# 同上
self.orders = []# 同上
super().__init__()
# 处理GET请求
def get(self, request, format=None):
return Response({'menu': self.menu, 'message': '欢迎光临老王烧烤(类视图版)!'})
# 处理POST请求
def post(self, request, format=None):
item_name = request.data.get('item')
if not item_name:
return Response({'error': '哥们,你还没说要点啥呢!'}, status=status.HTTP_400_BAD_REQUEST)
ordered_item = next((item for item in self.menu if item['name'] == item_name), None)
if not ordered_item:
return Response({'error': '抱歉,本店没有这个菜。'}, status=status.HTTP_404_NOT_FOUND)
order_id = len(self.orders) + 1
new_order = {'order_id': order_id, 'item': ordered_item}
self.orders.append(new_order)
return Response({
'message': f'类视图通知您:您点的{ordered_item["name"]}已下单,订单号{order_id}。'
}, status=status.HTTP_201_CREATED)
URL配置也要相应修改:
from django.urls import path
from .views import BarbecueAPIView
urlpatterns = [
path('api/bbq-cbv/', BarbecueAPIView.as_view(), name='bbq-api-cbv'),
]
看,用APIView,get和post方法泾渭分明,逻辑一目了然。以后要加put、delete方法,也只是在类里新增一个函数的事儿,非常符合“高内聚、低耦合”的编程美学。
总结:给你的代码“美个颜”
好了,今天的“Django视图包装课”就到这里。我们来简单总结一下:
- 原始Django视图:像自己买菜做饭,事事亲力亲为,虽然自由但繁琐。
- DRF的
@api_view:像请了个厨师助理,帮你处理了所有杂活(解析、渲染、检查),你只需要关心核心的“烹饪”逻辑。适合功能简单的API端点。 - DRF的
APIView:像开了一家正规餐厅,后厨分工明确(每个厨师负责一道工序),结构清晰,易于管理和扩展。适合复杂的API,尤其是完整的资源CRUD操作。
所以,别再让你辛辛苦苦写的API视图“素面朝天”了。赶紧拿起DRF这个“化妆盒”,给它“美个颜”,让它变得更强、更优雅、更好维护吧!
记住,优秀的程序员,不仅是实现功能,更是优雅地实现功能。 现在,就去重构你的代码吧!
5644

被折叠的 条评论
为什么被折叠?



