Search code examples
django-serializerdjango-jsonfield

Problem with Django Serializer involving nested JSON with null, and boolean values true or false


I've started using Django just late April this year and this is my first time to deal with bunch of JSONB data. Hope someone can give some inputs as to the cause of this exception:

Error in formatting: TypeError: the JSON object must be str, bytes or bytearray, not dict

So I inspected my data (I'm using PostgreSQL and it's coming from a Database View and the column name "decision" is of JSONB data type), the JSON data actually looks perfect like this:

{
  "some_id": "long-uuid-string",
  "case": {
    "name": "CaseA",
    "description": "DescriptionA",
    "case_date": "2021-06-23"
  },
  "justice": {
    "name": "JusticeA",
    "decision": [
      {
        "name": "DecisionA",
        "decision_date": "2021-06-23",
        "decision_flag": true,
        "decision_comment": null
      }
    ]
  }
}

But I noticed the "decision_flag": true and "decision_comment": null but I thought Django+Python should be able to convert but looks like it doesn't.

My understanding is that Django serializer should be able to automatically recognize those values - the null, true, and false - that I don't have to manually replace them or is there something in my model that I am missing? I tried to do print the value by print(instance.values('justice')[0]['justice']) so I can inspect but throwing the same exception. But my other JSON data case is good I can print it with print(instance.values('case')[0]['case']) and my assumption is because it does not have the null, true, and false values.

Here is my Model:

class Justice(models.Model):
    some_id = models.UUIDField(unique=True)
    case = models.JSONField()
    justice = models.JSONField()
    submission = models.JSONField()
    evaluation = models.JSONField()
    litigation = models.JSONField()
    denial = models.JSONField()
    triel = models.JSONField()

    def __str__(self):
        return str(self.some_id)

Here is my View:

class JusticeView(APIView):
  serializer_class = JusticeSerializer

  def get_object(self, request, **kwargs):
    some_id = self.kwargs['some_id']
    try:
      obj = get_object_or_404(Justice, pk=some_id)
    except Justice.DoesNotExist:
      return Response(status=status.HTTP_404_NOT_FOUND)
    return obj

  def get(self, request, **kwargs):
    data = self.get_object()
    serializer = JusticeSerializer(data)

    return Response(serializer.data)

Here is my Serializer:

class JusticeSerializer(serializers.ModelSerializer):

    case = serializers.JSONField()
    justice = serializers.JSONField()

    class Meta:
        model = Justice
        fields = '__all__'

Hope to get some help here. Cheers.


Solution

  • This is how I fixed this problem. I'm not sure if this is the best approach but at least this worked - if there is any better approach - the Django-way - I would definitely consider.

    I revised my model by changing all JSONField to TextField. Note that this model is only for my DB View - this isn't an actual table but all my sources in my "view_definition" have JSONB as data type.

    class Justice(models.Model):
        some_id = models.UUIDField(unique=True)
        case = models.TextField(null=True)
        justice = models.TextField(null=True)
        submission = models.TextField(null=True)
        evaluation = models.TextField(null=True)
        litigation = models.TextField(null=True)
        denial = models.TextField(null=True)
        triel = models.TextField(null=True)
    
        def __str__(self):
            return str(self.some_id)
    

    I kept my Serializer unchanged with serializers.JSONField() for every column in JSONB type. My DB View remain unchanged where JSON columns are in JSONB format.