0

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.

Pau1aAm7
  • 36
  • 8
  • Checkout this post here https://stackoverflow.com/questions/3768895/how-to-make-a-class-json-serializable – b26 Dec 21 '22 at 19:38
  • I have already checked that but couldn't figure out a way to solve my problem. – Pau1aAm7 Dec 21 '22 at 19:44

1 Answers1

1

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 syntax:

path("<str:code>/", MainView.as_view()),
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Niko
  • 3,012
  • 2
  • 8
  • 14
  • This solution works if I put the *code = request.data["ref_code"]* before the try/except. However it works when the ref_code is passed in the body of the post request, not in the url. In URL it gives me page not found even after adding the "/" as you suggested. – Pau1aAm7 Dec 22 '22 at 10:42
  • I do not want to sound impolite. But it is not only the "/" and it is not a suggestion. That is how the [URL Dispatcher](https://docs.djangoproject.com/en/4.1/topics/http/urls/#example) works ([A DRF Example](https://www.django-rest-framework.org/tutorial/3-class-based-views/)). As for passing data in the request body, you are correct, I will edit the answer and adapt the block to your needs. – Niko Dec 22 '22 at 11:41
  • Sorry, my bad way of expressing it. I had the / before but somehow I deleted it by mistake... – Pau1aAm7 Dec 22 '22 at 13:41