Royce
Royce

Reputation: 189

How to resolve Object of type 'AttributeError' is not JSON serializable?

I'm trying to understand Django DRF and am trying to do something complicated from my knowledge. In my application, I have invite keys, but I only want to allow the user to create an invite key after 3 days or if this is their first key. How do I create the serializer and view for this in a better way?

I'm using Django 2.1.5 and DRF 3.9.1

I have tried and read other questions on the web, but cannot get a good grasp on achieving what I want. All I have in mind is thin views, thick serializers. My view portion is not working correctly due to

Object of type 'AttributeError' is not JSON serializable

That error is coming from my view, that much I know.

My Model:

class Invite_Key(models.Model):
    STATUS_CHOICES = (
        ('valid', 'valid'),
        ('not_valid', 'not_valid'),
        ('banned', 'banned'),
    )

    # Foreign keys
    user_submitter = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        null=True,
        blank=True,
        related_name='user_submitter'
    )

    user_receiver = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        null=True,
        blank=True,
        related_name='user_receiver'
    )

    uuid = models.UUIDField(default=generate_ulid_as_uuid, editable=False, unique=True, null=False)
    open_uuid = models.UUIDField(default=uuid1, editable=False, unique=True, null=False)
    reason = models.TextField(validators=[bad_words, bad_words_inline, test_test])

    # Now are choices
    status = models.CharField(max_length=14, choices=STATUS_CHOICES, default="valid")

    # Now below are boolean
    is_taken = models.BooleanField(default=False)
    is_locked = models.BooleanField(default=False)

    claim_date = models.DateField(editable=True, null=True, blank=True)
    expire_date = models.DateField(editable=True, null=True, blank=True)

    # Now these are the time stamps
    created_at = models.DateTimeField(auto_now_add=True, editable=False)
    updated_at = models.DateTimeField(auto_now=True, editable=False)

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

    # An instance of our object temp used for later
    def __init__(self, *args, **kwargs):
        super(Invite_Key, self).__init__(*args, **kwargs)
        self.temp = ''

    # We can set attributes onSave of our data to the table
    def save(self, *args, **kwargs):
        if not self.id:
            # for expire date
            self.expire_date = datetime.now() + timedelta(days=7)

        super(Invite_Key, self).save(*args, **kwargs)

My Serializer:

class InviteKeyCreateAllSerializer(serializers.ModelSerializer):
    current_user = serializers.SerializerMethodField('_user')
    is_take = serializers.SerializerMethodField()
    class Meta:
        model = Invite_Key
        exclude = [
            'user_submitter',
            'user_receiver',
            'uuid',
            'status',
            'is_taken',
            'is_locked',
            'claim_date',
            'expire_date',
        ]

    # Use this method for the custom field
    def _user(self, obj):
        request = getattr(self.context, 'request', None)
        if request:
            return request.user

    def get_is_taken(self, obj):
        return False

    def get_status(self, obj):
        return 'valid'

    # end of custom fields

    def create(self, validated_data):
        key = Invite_Key(
            user_submitter=validated_data['request.user'],
        )
        key.set_user_submitter(validated_data['user_submitter'])
        key.save()
        return key

My View

class InviteKeyAllCreateView(generics.CreateAPIView):
    """
    POST invitekey/
    """
    serializer_class = InviteKeyCreateAllSerializer
    permission_classes = (IsAuthenticated,)

    def post(self, request, *args, **kwargs):
        user = self.request.user
        try:
            # get user count of keys
            cur_key_count = Invite_Key.objects.filter(user_submitter_id=user.id).order_by('-created_at').count()
            if cur_key_count > 0:
                # now we get the latest one
                check_key = Invite_Key.object.filter(user_submitter_id=user.id)[0]
                now = datetime.now()
                if now-timedelta(days=3) <= datetime.datetime.strptime(check_key['created_at'], "%Y-%m-%dT%H:%M:%S.%fZ"):
                    serialized_data = InviteKeyCreateAllSerializer(data=request.data)
                    serialized_data.is_valid(raise_exception=True)
                    serialized_data.save()
                else:
                    return Response(
                        data={
                            "message": "Sorry, you have recently created an Invite Key, try again some other time."
                        },
                        status=status.HTTP_400_BAD_REQUEST
                    )
        except Exception as e:
            return Response(
                data={
                    "message": "The Invite Key could not be created.",
                    "error": e
                },
                status=status.HTTP_400_BAD_REQUEST
            )

I expected an Invite Key to be created with creating an http post request, and the view would check if the user has made keys, then get the latest key, then check the key was 3 days old before creating a new one, and the serializer would populate the missing data from the post request.

The actual result was I get an AttributeError. Also, is it possible to move most of my view logic to the serializer? Can someone give me hints? I was looking for something similar in the DRF Docs for Serializers and Views and can't find much.

If I'm missing some info let me know, thanks...

EDIT: Added model class EDIT: I changed to str(e), and my error is now:

type object 'Invite_Key' has no attribute 'object'

EDIT: Added Error-Traceback

Django Version: 2.1.5
Python Version: 3.6.8
Installed Applications:
['django.contrib.admin.apps.SimpleAdminConfig',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'rest_framework',
 'corsheaders',
 'djmoney',
 'api',
 'main',
 'rssparser',
 'invite_system',
 'user_system']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'corsheaders.middleware.CorsMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']



Traceback:

File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py" in inner
  34.             response = get_response(request)

File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
  126.                 response = self.process_exception_by_middleware(e, request)

File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
  124.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/usr/local/lib/python3.6/site-packages/django/views/decorators/csrf.py" in wrapped_view
  54.         return view_func(*args, **kwargs)

File "/usr/local/lib/python3.6/site-packages/django/views/generic/base.py" in view
  68.             return self.dispatch(request, *args, **kwargs)

File "/usr/local/lib/python3.6/site-packages/rest_framework/views.py" in dispatch
  495.             response = self.handle_exception(exc)

File "/usr/local/lib/python3.6/site-packages/rest_framework/views.py" in handle_exception
  455.             self.raise_uncaught_exception(exc)

File "/usr/local/lib/python3.6/site-packages/rest_framework/views.py" in dispatch
  492.             response = handler(request, *args, **kwargs)

File "/opt/service/api/src/invite_system/views.py" in post
  229.             check_key = Invite_Key.object.filter(user_submitter_id=user.id).order_by('-created_at')[0]

Exception Type: AttributeError at /api/v1/invitekey
Exception Value: type object 'Invite_Key' has no attribute 'object'

EDIT: I am debugging and am stuck on how to structure this if statement below.

Error:

'Invite_Key' object is not subscriptable

Point of Error:

            now = datetime.now()
            if now-timedelta(days=3) <= datetime.strptime(check_key['created_at'], "%Y-%m-%dT%H:%M:%S.%fZ"):
                serialized_data = InviteKeyCreateAllSerializer(data=request.data)

The if statement cannot evaluate check_key['created_at'] to be formatted. WHat is the correct way to do this? I'm using Postgres for the timestamps.

Upvotes: 1

Views: 8993

Answers (1)

JPG
JPG

Reputation: 88509

.......
except Exception as e:
return Response(
    data={
        "message": "The Invite Key could not be created.",
        "error": e    },
    status=status.HTTP_400_BAD_REQUEST)

In the above snippet, the variable e the object of any of the valid Pycthon Exception class and obviously its not serializable.


Solution

represent the object in string format

.......
except Exception as e:
return Response(
    data={
        "message": "The Invite Key could not be created.",
        "error": str(e)
    },
    status=status.HTTP_400_BAD_REQUEST)

UPDATE-1

It should be objects instead of object (charecter s is missing)

check_key = Invite_Key.objects.filter(user_submitter_id=user.id)[0]

Upvotes: 3

Related Questions