You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django视图开发:实现返回JSON/JSONP格式的国家数据

关于Django视图返回JSON/JSONP的测试与实现优化建议

我来帮你梳理下这两个问题的解决方案和优化点:


1. 测试视图返回数据的标准方法

测试Django视图的核心是模拟请求并验证响应,这里有几种常用的标准方法:

  • 使用Django自带的TestCase框架:这是最规范的自动化测试方式,能覆盖大部分场景,示例代码如下:
from django.test import TestCase, Client
import json

class CountryViewTest(TestCase):
    def setUp(self):
        # 预先创建测试用的大洲和国家数据
        self.continent = Continent.objects.create(code='EU', name='Europe')
        self.country = Country.objects.create(
            code='FI', name='Finland', continent=self.continent,
            area=337030, population=5244000, capital='Helsinki'
        )
        self.client = Client()

    def test_country_json_response(self):
        response = self.client.get('/your/view/path/EU/FI/')
        # 断言响应状态码正常
        self.assertEqual(response.status_code, 200)
        # 断言内容类型为JSON
        self.assertEqual(response['Content-Type'], 'application/json')
        # 解析响应并验证数据准确性
        data = json.loads(response.content)
        self.assertEqual(data['area'], 337030)
        self.assertEqual(data['capital'], 'Helsinki')

    def test_country_jsonp_response(self):
        response = self.client.get('/your/view/path/EU/FI/?callback=myCallbackFunction')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response['Content-Type'], 'application/javascript')
        # 验证JSONP格式是否正确
        self.assertIn('myCallbackFunction({', response.content.decode())
  • 手动测试工具:

    • 用curl命令快速验证:比如 curl http://localhost:8000/your/view/path/EU/FI/,或者带callback参数的 curl http://localhost:8000/your/view/path/EU/FI/?callback=testFunc
    • 用Postman、Insomnia等GUI工具,直观发送请求并查看响应格式和数据。
  • 如果使用Django REST Framework:可以用DRF提供的APITestCase和APIClient,更便捷地处理序列化和API场景的测试。


2. 当前实现的问题与优化建议

你的当前代码存在不少需要修正的细节,我逐一拆解:

首先是Country模型的严重错误

你在模型的__init__方法里定义字段是完全错误的!Django模型的字段必须定义为类属性,否则ORM无法识别这些字段,数据库迁移时也不会创建area、population、capital这些列。正确的模型定义应该是:

class Country(models.Model):
    name = models.CharField(max_length=60, default='', unique=True)
    code = models.CharField(max_length=3, default='', unique=True)
    continent = models.ForeignKey(Continent, related_name='countries', on_delete=models.CASCADE)
    # 把字段移到类属性层面!
    area = models.PositiveIntegerField(default=0)
    population = models.PositiveIntegerField(default=0)
    capital = models.CharField(max_length=60, default='')

    def __str__(self):
        return f'{self.name} {self.code} {self.capital} {self.population} {self.area} {self.continent}'

    class Meta:
        ordering = ["name"]
        verbose_name_plural = "countries"

注意:Django 2.0+中外键必须指定on_delete参数,比如on_delete=models.CASCADE

视图实现的不良/错误实践

  1. 遍历所有Country匹配code效率极低:当数据库中有大量国家数据时,循环遍历的方式会严重拖慢响应速度。正确做法是直接用ORM查询:
try:
    # 同时过滤大洲和国家代码,逻辑更严谨
    country = Country.objects.get(code=country_code, continent__code=continent_code)
except Country.DoesNotExist:
    return HttpResponse(status=404)
  1. 手动构造序列化字典易出错:手动提取字段容易遗漏或写错键名,建议用Django自带序列化工具或DRF序列化器。比如用django.core.serializers:
from django.core.serializers import serialize
# 只序列化需要的字段
serialized_data = serialize('json', [country], fields=('area', 'population', 'capital'))
# 转换为字典格式
data_dict = json.loads(serialized_data)[0]['fields']
json_str = json.dumps(data_dict, indent=4)
  1. 缺少JSONP处理逻辑:需要检查请求的GET参数中是否存在callback,如果有就把JSON数据包裹在回调函数里,并修改内容类型:
callback = request.GET.get('callback')
if callback:
    response_content = f"{callback}({json_str})"
    return HttpResponse(response_content, content_type="application/javascript")
else:
    return HttpResponse(json_str, content_type="application/json")
  1. 初始代码的错误操作:你最初的代码里直接country = Country(code=country_code)然后save(),这会创建一个新的国家对象存入数据库,完全不符合“查询已有数据”的需求,一定要删除这类代码。

优化后的完整视图示例

import json
from django.http import HttpResponse
from django.core.serializers import serialize
from .models import Country

def country_json(request, continent_code, country_code):
    try:
        country = Country.objects.get(code=country_code, continent__code=continent_code)
    except Country.DoesNotExist:
        return HttpResponse(status=404)
    
    # 序列化指定字段
    serialized_data = serialize('json', [country], fields=('area', 'population', 'capital'))
    data_dict = json.loads(serialized_data)[0]['fields']
    json_str = json.dumps(data_dict, indent=4)
    
    # 处理JSONP请求
    callback = request.GET.get('callback')
    if callback:
        response_content = f"{callback}({json_str})"
        return HttpResponse(response_content, content_type="application/javascript")
    else:
        return HttpResponse(json_str, content_type="application/json")

内容的提问来源于stack exchange,提问作者Grak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:13:19