Skip to main content
 首页 » 编程设计

python之带分页的 Django API 列表之页面不是 JSON 可序列化的

2024年08月19日32mfryf

我正在尝试为带分页的列表创建 Django API,但出现此错误

TypeError: Object of type 'Page' is not JSON serializable 

以下是我的API代码:

@api_view(['POST']) 
def employee_get_list_by_page(request): 
    # ----- YAML below for Swagger ----- 
    """ 
    description: employee_get_list_by_page 
    parameters: 
      - name: token 
        type: string 
        required: true 
        location: form        
      - name: page 
        type: string 
        required: true 
        location: form    
      - name: page_limit 
        type: string 
        required: true 
        location: form                    
    """ 
    token = request.POST['token'] 
    try:   
        auth_employee = AuthEmployeeSessionToken.objects.get(token=token)  
 
    except AuthEmployeeSessionToken.DoesNotExist:    
        return Response("Invalid Token", status=status.HTTP_406_NOT_ACCEPTABLE) 
 
    employee_list = Employee.objects.filter(company = auth_employee.employee.company.id)  
 
 
    page = request.GET.get('page', request.POST['page']) 
    paginator = Paginator(employee_list, request.POST['page_limit']) 
 
    try: 
        employees = paginator.page(page) 
    except PageNotAnInteger: 
        employees = paginator.page(request.POST['page']) 
    except EmptyPage: 
        employees = paginator.page(paginator.num_pages) 
 
    return Response(employees,status=status.HTTP_200_OK) <-- passing employees probably cause this error that employees as Page is not JSON serializable. 

这是我的模型 https://gist.github.com/axilaris/89b2ac6a7762f428ad715f4916f43967 . as_dict 通知我有这个 .as_dict() 来创建我的 json 以进行响应。我将它用于单个请求,但对于列表,我不确定它是如何完成的。

  1. API 如何查询支持分页的列表?
  2. 附带问题,我希望 JSON 仅列出我想要的字段。

请您参考如下方法:

我刚刚尝试重新创建它,并且我看到了一些修复它的方法。

首先,JSON 将无法解析 Page 对象,也无法解析 page.object_list 属性下的 QuerySet。它会说 “'Employee' 类型的对象不是 JSON 可序列化的”。

所以为了解决这个问题,我会尝试:

employee_list = Employee.objects.filter(company = auth_employee.employee.company.id).values().order_by('id')  
 
page = request.GET.get('page', request.POST['page']) 
paginator = Paginator(employee_list, request.POST['page_limit']) 
 
try: 
    employees = paginator.page(page) 
except PageNotAnInteger: 
    employees = paginator.page(request.POST['page']) 
except EmptyPage: 
    employees = paginator.page(paginator.num_pages) 
 
return Response(list(employees) ,status=status.HTTP_200_OK) 

首先,我们在员工查询集上使用 .values(),因为可以使用 list(employees) 解析此调用的结果 ValuesQuerySet。在 Page 类内部,它们在返回任何结果之前以这种方式评估实例中的对象列表。

最后,由于 JSON 无法序列化 Page 类,我们只需调用 list(Page) 即可返回一个列表。这是可行的,因为 Page 实现了 __getitem__ 并返回了底层的 object_list。

此外,您可能会发现某些数据类型会引发 JSON 序列化错误(values() 将为 DateTime 字段返回 DateTime 对象)。在我的测试中,我遇到了一个问题,Object of type 'datetime' is not JSON serializable。如果发生这种情况,您需要使用不同的 JSON 编码器或扩展您自己的编码器。 DjangoJSONEncoder 可以在 django.core.serializers.json.DjangoJSONEncoder 中找到,并处理 django 中的日期时间、uuid、小数和其他常见数据类型。

编辑:您提到您的模型代码为:

class Employee(models.Model): 
 
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='employee') 
    company = models.ForeignKey(Company) 
    username = models.CharField(max_length=30, blank=False) 
    email = models.CharField(max_length=30, blank=False) 
    first_name = models.CharField(max_length=30, blank=False) 
    last_name = models.CharField(max_length=30, blank=False) 
 
    created_at = models.DateTimeField(auto_now_add=True) 
    updated_at = models.DateTimeField(auto_now=True) 
 
    def __str__(self): 
        return self.user.username 
 
    def as_dict(self): 
 
        return {"id": "%d" % self.id, 
                "company": self.company.as_dict(), 
                "username": self.username if self.username else "", 
                "email": self.email if self.email else "", 
                "first_name": self.first_name if self.first_name else "", 
                "last_name": self.last_name if self.last_name else "", 
                "tel":self.tel if self.tel else "",                
                "created_at":self.created_at.strftime('%Y-%m-%d %H:%M'), 
                "updated_at":self.updated_at.strftime('%Y-%m-%d %H:%M')} 

因为你有这个 as_dict 方法,我们可以用它来呈现你的员工的表示,而不是依赖于 .values()。方法如下:

employee_list = Employee.objects.filter(company = auth_employee.employee.company.id).order_by('id')  
 
page = request.GET.get('page', request.POST['page']) 
paginator = Paginator(employee_list, request.POST['page_limit']) 
 
try: 
    employees = paginator.page(page) 
except PageNotAnInteger: 
    employees = paginator.page(request.POST['page']) 
except EmptyPage: 
    employees = paginator.page(paginator.num_pages) 
#  Here we map a lambda function over the queryset of Models to return the dictionary representation for each element in the list 
employees_page = list( 
    map(lambda employee: employee.as_dict(), list(employees)) 
) 
return Response(employees_page ,status=status.HTTP_200_OK)