0

I realy tried to find answer to my question, but don't know what should I do. I found following question and they didn't help me. question1, question2, docs

I got different values with different functions that I used. Sometimes None value
sometimes TypeError: Object of type 'method' is not JSON serializable
and AttributeError: 'str' object has no attribute 'status_code' and this
TypeError: 'method' object is not iterable

But i didn't still find solution to solve my problem. Here is my Page model it has InlinePanel that takes some data from another 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)

And here is the model that related to my 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')
    ...

UPDATE

Sorry if I ask too noob questions, but I'm new in programming. @gasman these are the ways I used.

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

Just changed loop from for pn in self.matches: to 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'

As I said, I do not know how this conversion works, so I tried to guess.

khashashin
  • 1,058
  • 14
  • 40
  • 1
    Please show us the code that you've tried so far - it'll help you understand where you're going wrong, better than someone simply writing the code for you. – gasman Feb 17 '18 at 09:13

1 Answers1

5

The important lesson here is to try to solve one problem at once. You're trying to deal with returning a response from serve at the same time as constructing some JSON, and it doesn't look like you're getting anywhere because fixing the first half of the problem just leads you to an error in the second half.

Let's make sure we know how to return something from serve, even if it's just something useless:

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

This will fail with something like: 'str' object has no attribute 'get'. This tells us that returning a string is the wrong thing to do: whatever object we return, Wagtail is expecting it to have a get attribute. Looking at the documentation, we can see that it's supposed to be an HttpResponse object:

from django.http import HttpResponse

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

This works, so now we know that whatever other stuff we do with JSON in this method, we need to end with return HttpResponse(some_result).

So now let's bring in json.dumps. Again, let's start with some fake data to make sure we're using it right:

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)

Hopefully this works too, so let's bring in the real data:

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)

This now fails with something like: TypeError: Object of type 'GroupstageTournamentModel' is not JSON serializable. So now you have to ask: what's changed here? What's different about my real data from the 'fake' data? If you're not sure, add in a debugging line to see what's going on:

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)

The error message hopefully makes it clear: the value you're passing to json.dumps contains GroupstageTournamentModel objects, and JSON doesn't know how to deal with those. You need to convert them into basic values such as dicts, and that means specifying how each individual field is meant to appear in the output:

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)

In summary - when you encounter an error message:

  • don't just abandon your code and try something else;
  • look at what the error message is telling you, and especially, what line of code it's coming from;
  • see if there's a way to reduce it to a simpler case that does succeed, then work your way back up to the real solution.
gasman
  • 23,691
  • 1
  • 38
  • 56
  • Thank you very much it was rly great explanation. Many debugging techniques and tricks come with experience, I did not even think of getting them out via print(). But unfortunately not all part of my code works. And now I'm too shy to ask again :). One piece of data that I want to get is a wagtail image chooser which is in another model. And when I add this part to my conversion like:`'team_2_logo': match.team_2.team_logo,` I get an error.`TypeError: Object of type 'Image' is not JSON serializable`.I have to convert this part too, but i don't know how it will match my data if do it separately – khashashin Feb 18 '18 at 03:22