pythonjsondjangodjango-rest-frameworkzoneinfo

DRF TimeZoneField: not JSON serializable error


I have django model:

from django.db import models
from timezone_field import TimeZoneField

class Client(models.Model):
    time_zone = TimeZoneField(choices_display='WITH_GMT_OFFSET')

And APIView for this model:

class ClientAPIView(APIView):
    def get(self, request: Request, pk: int, format=None) -> Response:

        client = get_object_or_404(Client, pk=pk)
        client_serializer = ClientListSerializer(client)
        return Response(client_serializer.data)

I get an error from GET request: TypeError: Object of type ZoneInfo is not JSON serializable

Serializer code:

class ClientListSerializer(serializers.ModelSerializer):
    class Meta:
        model = Client
        fields = ('id', 'time_zone')

How fix code of Model, Serializer or View (I don't know what exactly) so that instead of ZoneInfo there is just a string.

UPDATE: if change serializer:

class ClientListSerializer(serializers.ModelSerializer):
    time_zone = serializers.CharField(max_length=256)

GET request will be work, but POST request give me error, if send invalid string for time zone. For example {"time_zone": "invalid string"} Result: django.core.exceptions.ValidationError: ["Invalid timezone 'invalid string'"]

My POST method code:

    def post(self, request: Request, format=None) -> Response:
        client_serializer = ClientSerializer(data=request.data)
        if not client_serializer.is_valid():
            return Response(client_serializer.errors, status=status.HTTP_400_BAD_REQUEST)

        client_serializer.save()
        return Response('client was created successfully', status=status.HTTP_201_CREATED)

SOLVED

Maybe this is not the best solution, but now requests work correctly after modify serializer:

import pytz
from rest_framework import serializers


class ClientSerializer(serializers.ModelSerializer):
    time_zone = serializers.ChoiceField(choices=pytz.all_timezones)

    class Meta:
        model = Client
        fields = ('id', 'time_zone')

If you know better solution, share with me


Solution

  • Django 4.0+

    Django 4.0 makes zoneinfo the default implementation. Support for pytz is now deprecated and will be removed in Django 5.0.

    from zoneinfo import available_timezones
    
    from rest_framework import serializers
    
    
    class ClientSerializer(serializers.ModelSerializer):
        time_zone = serializers.ChoiceField(choices=available_timezones())
    
        class Meta:
            model = Client
            fields = ['id', 'time_zone', ]