【问题标题】:Django API list with pagination - Page is not JSON serializable带有分页的 Django API 列表 - 页面不是 JSON 可序列化的
【发布时间】:2020-03-10 07:50:49
【问题描述】:

我正在尝试为带有分页的列表创建 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 仅列出我想要的字段的附带问题。

【问题讨论】:

    标签: python json django pagination serialization


    【解决方案1】:

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

    首先,JSON 将无法解析 Page 对象,也无法解析 page.object_list 属性下的 QuerySet。它会说"Object of type 'Employee' is not JSON serialisable"

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

    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)
    

    【讨论】:

    【解决方案2】:

    如果任何使用 Django Rest Framework (DRF) 的人发现这个,DRF serializers 可以将page.object_list 序列化为 JSON。当然,更好的方法是在 DRF view(set)s 中指定pagination_classhttps://www.django-rest-framework.org/api-guide/pagination/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-02-12
      • 1970-01-01
      • 2017-06-18
      • 2013-04-29
      • 1970-01-01
      • 2018-09-12
      • 2013-05-23
      • 2015-02-24
      相关资源
      最近更新 更多