Home > Blockchain >  TypeError: Object of type User is not JSON serializable
TypeError: Object of type User is not JSON serializable

Time:12-23

I am quite new to Django and I am building a simple referral system where a code is autogenerated for the user and when this code is called, the API should return the user by which this code was referred. However I am experiencing some difficulties to return the username, getting the error TypeError: Object of type User is not JSON serializable. Below I am posting my code (please ignore the unused imports, I was trying many things and I need to clean the code later)

views.py `

from rest_framework.decorators import api_view
from rest_framework.response import Response
import json, requests
from rest_framework.views import APIView
from django.http import JsonResponse, HttpResponse
from django.core import serializers
from django.core.serializers import serialize
import ast
from rest_framework.parsers import JSONParser


class MainView(APIView):
    def post(self, request):
        code = request.data["ref_code"]
        print(str(code))
        try:
            profile = ReferralSys.objects.get(code=code)
            print(profile)
            request.session["ref_profile"] = profile.user
            username = profile.user.username
            print(username)
            print(type(username))
            # return HttpResponse("user is here", user)
        except:
            pass
            print(request.session.get_expiry_date())
        return Response(f"{profile.user.username}")

models.py

from django.db import models
from django.contrib.auth.models import User
from .utils import generate_ref_code


class ReferralSys(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    bio = models.TextField(blank=True)
    code = models.CharField(max_length=12, blank=True)
    recommented_by = models.ForeignKey(
        User, on_delete=models.CASCADE, blank=True, null=True, related_name="ref_by"
    )
    updated = models.DateTimeField(auto_now=True)
    created = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f"{self.user.username}-{self.code}"

    def get_recommended_profiles(self):
        pass

    def save(self, *args, **kwargs):
        if self.code == "":
            code = generate_ref_code()
            self.code = code
        super().save(*args, **kwargs)

utils.py

import uuid


def generate_ref_code():
    code = str(uuid.uuid4()).replace("-", "")[:12]
    return code

urls.py

from django.contrib import admin
from django.urls import path
from .views import MainView


urlpatterns = [
    path("admin/", admin.site.urls),
    path("", MainView.as_view()),
    path("str:<ref_code>", MainView.as_view()),
]

Thank you in advance for the help.

PS: I am following this tutorial https://www.youtube.com/watch?v=QZfflGvRQrc&t, but instead of using templates I want to use APIView.

CodePudding user response:

What happens is that Django sessions serializes data using JSON. When writing:

request.session["ref_profile"] = profile.user

You are trying to insert a model inside the session, thus the error. One basic and simple way, is to parse the desired data into a JSON:

from rest_framework.response import Response
from rest_framework.views import APIView
from .models import ReferralSys
import json

class MainView(APIView):
    def post(self, request, code=None):
        if code is None:
            code = request.data['code']

        try:
            profile = ReferralSys.objects.get(code=code)
            user = {
                'username': profile.user.username,
                'email': profile.user.email
            }
            user_json = json.dumps(user)
            request.session["ref_profile"] = user_json

        except:
            pass
            print(request.session.get_expiry_date())
        return Response(f"{profile.user.username}")

Of course, there are tradeoffs and I recommend you to read the documentation in order to understand them. There is also another mistake in the form of how you are passing (and retrieving) the extra keyword argument in the URL, the right sintax:

path("<str:code>/", MainView.as_view()),
  • Related