在 serve 方法中将值转换为 json。鹡鸰

Converting value to json inside serve method. Wagtail

我真的很想找到我的问题的答案,但不知道该怎么办。我发现了以下问题,但他们没有帮助我。 question1, , docs

我使用的不同函数得到了不同的值。有时None
有时 TypeError: Object of type 'method' is not JSON serializable
AttributeError: 'str' object has no attribute 'status_code' 和这个
TypeError: 'method' object is not iterable

但我仍然没有找到解决问题的方法。 这是我的页面模型,它有 InlinePanel 从另一个 class:

获取一些数据
class ScreencastPage(Page):
    content_panels = Page.content_panels + [
        InlinePanel(
            'groupstage_screencast_relationship', label="Choose Teams",
            panels=None, max_num=2),
    ]

    parent_page_types = ['home.HomePage']

    def matches(self):
        matches = [
            n.match for n in self.groupstage_screencast_relationship.all()
        ]

        return matches

    def serve(self, request):
        if request.is_ajax():
            # TODO Convert self.mathes to JSON and return it
        else:
            return super(ScreencastPage, self).serve(request)

这是与我的ScreencastPage

相关的模型
@register_snippet
class GroupstageTournamentModel(ClusterableModel):
    number = models.PositiveSmallIntegerField(
        verbose_name="Match №:")
    starts_at = models.DateTimeField()
    # Team 1
    team_1 = models.ForeignKey(
        TeamRooster,
        null=True, verbose_name='Erste Team',
        on_delete=models.SET_NULL,
        related_name="+",
    )
    team_1_dress = ColorField(blank=True, verbose_name='Dress')
    team_1_first_halftime_score = models.PositiveSmallIntegerField(blank=True, default=0, verbose_name='Resultat 1. HZ')
    team_1_first_halftime_point = models.PositiveSmallIntegerField(blank=True, default=0, verbose_name='Punkte 1. HZ')
    ...

更新

对不起,如果我问的问题太菜鸟了,但我是编程新手。 @gasman 这些是我使用的方式。

1

def serve(self, request):
    if request.is_ajax():
        lst = []
        d = {}
        for pn in self.matches:
            d['mpn']=pn
            lst.append(d)
        return json.dumps([dict(mpn=pn) for pn in lst])

returns: TypeError: 'method' object is not iterable

2

刚刚将循环从 for pn in self.matches: 更改为 for pn in self.matches():

def serve(self, request):
    if request.is_ajax():
        lst = []
        d = {}
        for pn in self.matches():
            d['mpn']=pn
            lst.append(d)
        return json.dumps([dict(mpn=pn) for pn in lst])

returns: TypeError: Object of type 'GroupstageTournamentModel' is not JSON serializable

3

def serve(self, request):
    if request.is_ajax():
        if isinstance(self.matches, (list, dict, str, int, float, bool, type(None))):
            data = JSONEncoder.default(self.matches())
            return data
        elif '_python_object' in self.matches():
            data = pickle.loads(str(self.matches['_python_object']))
            return data

returns: ValueError: The view wagtail.wagtailcore.views.serve didn't return an HttpResponse object. It returned None instead.

4

def serve(self, request):
    if request.is_ajax():
        data = [
            n.match for n in self.groupstage_screencast_relationship.all()
        ]
        return data

returns: AttributeError: 'list' object has no attribute 'status_code'

5

def serve(self, request):
    if request.is_ajax():
        data = [
            n.match for n in self.groupstage_screencast_relationship.all()
        ]
        if isinstance(data, (list, dict, str, int, float, bool, type(None))):
            conv_data = json.JSONEncoder.default(data)
            return conv_data

returns: TypeError: default() missing 1 required positional argument: 'o'

正如我所说,我不知道这种转换是如何进行的,所以我试着猜测。

这里重要的一课是尝试一次解决一个问题。您正在尝试处理 return 来自 serve 的响应,同时构建一些 JSON,但看起来您没有任何进展,因为修复了第一个一半的问题只会导致你在后半部分出错。

让我们确保我们知道如何从 serve 中 return 某些东西 ,即使它只是一些无用的东西:

def serve(self, request):
    if request.is_ajax():
        return "hello world!"
    else:
        return super(ScreencastPage, self).serve(request)

这将失败并显示如下内容:'str' object has no attribute 'get'。这告诉我们 return 字符串是错误的做法:无论我们 return 什么对象,Wagtail 都期望它具有 get 属性。查看the documentation,我们可以看到它应该是一个HttpResponse对象:

from django.http import HttpResponse

def serve(self, request):
    if request.is_ajax():
        return HttpResponse("hello world!")
    else:
        return super(ScreencastPage, self).serve(request)

这行得通,所以现在我们知道无论我们在这个方法中使用 JSON 做什么其他事情,我们都需要以 return HttpResponse(some_result).

结束

现在让我们引入 json.dumps。同样,让我们​​从一些假数据开始,以确保我们正确使用它:

import json
from django.http import HttpResponse

def serve(self, request):
    if request.is_ajax():
        result = ['first match', 'second match']
        json_output = json.dumps(result)
        return HttpResponse(json_output)
    else:
        return super(ScreencastPage, self).serve(request)

希望这也能奏效,让我们引入真实数据:

import json
from django.http import HttpResponse

def serve(self, request):
    if request.is_ajax():
        result = self.matches()
        json_output = json.dumps(result)
        return HttpResponse(json_output)
    else:
        return super(ScreencastPage, self).serve(request)

这现在失败了:TypeError: Object of type 'GroupstageTournamentModel' is not JSON serializable。所以现在你不得不问:这里发生了什么变化?我的真实数据与 'fake' 数据有何不同?如果您不确定,请添加调试行以查看发生了什么:

import json
from django.http import HttpResponse

def serve(self, request):
    if request.is_ajax():
        result = self.matches()
        print(result)  # this output will appear in the terminal / command prompt
        json_output = json.dumps(result)
        return HttpResponse(json_output)
    else:
        return super(ScreencastPage, self).serve(request)

错误消息希望能清楚地表明:您传递给 json.dumps 的值包含 GroupstageTournamentModel 个对象,而 JSON 不知道如何处理这些对象。您需要将它们转换为基本值,例如字典,这意味着指定每个字段在输出中的显示方式:

def serve(self, request):
    if request.is_ajax():
        result = [
            {
                'number': match.number,
                'team1': match.team_1.name,
                # ...
            }
            for match in self.matches()
        ]
        json_output = json.dumps(result)
        return HttpResponse(json_output)
    else:
        return super(ScreencastPage, self).serve(request)

总结 - 当您遇到错误信息时:

  • 不要只是放弃您的代码并尝试其他东西;
  • 查看错误消息告诉您的内容,尤其是它来自哪一行代码;
  • 看看是否有办法将其简化为确实成功的更简单的情况,然后再回到真正的解决方案。