top of page

Creating Django Rest Framework's Profile API

Updated: Dec 3, 2022

Planning:

1. Create profile API
  • Handles registration of new users

  • Validate profile Data

2. Listing Existing Profiles.
  • Search for profile and name

  • Email and Name

API URLS
127.0.0.1:8000/api/profiles
  • List all profile when HTTP GET method is called.

  • Create new Profile when HTTP POST method is called.

Implementation:


serializer.py


from rest_framework import serializers

from profiles_api import models


class HelloSerializers(serializers.Serializer):

name=serializers.CharField(max_length=10)

age = serializers.IntegerField()


class UserProfileSerializer(serializers.ModelSerializer):


"""Serialize a user profile object """

""" Note: Define a meta class , the way you work with ModelSerializer is to use a meta class to configure a serializer to point to a specific model in our project. Class Meta will point to UserProfile models . Here need to specify list of fields in our model that has to manage through serializer """


class Meta:

model = models.UserProfile

fields = ('id', 'email','name', 'password')

extra_kwargs = {

'password' : { 'write_only' : True, 'style' :{'input_type' :'password'}}

}


"""Now override the create function of DRF so as to save password in hash type not in simple readable format"""


"""Whenever we create a profile object with our serializer. It will validate the object and

fields, provided to serializer and then it will call the create function and passing it in validated_data"""


def create(self, validated_data):

"""create and return new user"""

user = models.UserProfile.objects.create_user(

email=validated_data['email'],

name=validated_data['name'],

password=validated_data['password']

)

return user

"""Note: it will override the create function and call our create_user function from models.py file."""


def update(self, instance, validated_data):

"""Handle update user account """

if 'password' in validated_data:

password=validated_data.pop('password')

instance.set_password(password)

return super().update(instance, validated_data)


"""The default update logic for DRF ModelSerializer will take whatever fields are

provided(in our case name, email and password) and pass them directly to the model.

This is fine with the fields like name and email, However the password field require some additional logic

to hash the pasword before saving the update. Now password will be save in hash or non readable form.

Therefore we override the update() method to add this logic to check the presence of password in validated_data

which is passed from DRF when updating an object.

If the fields exists we will pop the password from the validated_data dictionary and set it using set_password

which is save the password in Hash type.

Once that done we use super().update() to pass the values to the existing DRF update method,

to handle the remaining fields"""


views.py


from rest_framework.views import APIView

from rest_framework.response import Response

from rest_framework import status

from profiles_api import serializers

from rest_framework import viewsets

from profiles_api import models


ss = serializers.HelloSerializers

def get(self, request, format=None):

an_api = [

"Uses Standard HTTP methods as function(get, post,put,delete)",


"It is similar to traditional Django view",


"Gives you control over ur application and logic",


"It mapped manually to URL's"

]

print("Log for ans_api",type(an_api))

return Response({"message":"hello world", "an_api" : an_api})


def post(self, request):

serializer = self.serializer_class(data=request.data)

print("Log for serializer", type(serializer))

if serializer.is_valid():

name=serializer.validated_data.get("name")

age=serializer.validated_data.get("age")

message = f"hello {name, age}"

return Response({'message' : message})

else:

return Response(serializer.errors,

status = status.HTTP_400_BAD_REQUEST)




def put(self, request, pk=None):

"""Handling update an object"""

return Response({'method':'PUT'})


def patch(self, request, pk=None):

"""Handling partial update of an object """

return Response({'method' : 'PATCH'})


def delete(self, request,pk=None):

"""Delete an Object """

return Response({'method' : 'DELETE'})


class HelloViewSet(viewsets.ViewSet):

"""Test API ViewSet """

serializer_class = serializers.HelloSerializers

def list(self, request):

"""Return a hello Message """

a_viewset = [

"uses action such as (list, create, retrive, update, partial_update)",

"Automatically map to URL's using routers",

"Provides more functionality with less code"

]

return Response({'message' : "Hello", 'a_viewset':a_viewset})

def create(self,request):

"""create a new hello world message"""

serializer=self.serializer_class(data=request.data)

if serializer.is_valid():

name=serializer.validated_data.get('name')

age=serializer.validated_data.get('age')

message=f'Hello{name, age}!'

return Response({'message' : message})

else:

return Response(serializer.errors,

status = status.HTTP_400_BAD_REQUEST)

def retrive(self, request, pk=None):

"""Handles getting an object by ID """

return Response({'http_method': 'GET'})


def update(self, request, pk=None):

"""Handles update an object"""

return Response({'http_method':'PUT'})

def partial_update(self, request, pk=None):

"""Handles partial updates"""

return Response({'http_method':'PATCH'})

def destroy(self, request, pk=None):

return Response({'http_method' : 'DELETE'})


class UserProfileViewSet(viewsets.ModelViewSet):

"""Handling creating and updating profiles """

serializer_class=serializers.UserProfileSerializer

queryset=models.UserProfile.objects.all()


urls.py


from django.urls import path, include

from profiles_api import views

from rest_framework.routers import DefaultRouter


router=DefaultRouter()

router.register('hello-viewset', views.HelloViewSet, base_name='hello_viewset')

"""Note: base_name is use to retrive the URL in our router """

router.register('profile', views.UserProfileViewSet)

"""Note: We dont need to give basename here because UserProfileViewSet has a queryset

that takes a name from models."""

urlpatterns = [

path('hello-view/', views.HelloApiVIew.as_view()),

path('', include(router.urls))

]


models.py


from django.db import models

from django.contrib.auth.models import AbstractBaseUser

from django.contrib.auth.models import PermissionsMixin

from django.contrib.auth.models import BaseUserManager



class UserProfileManager(BaseUserManager):


def create_user(self, email, name, password=None):

if not email:

raise ValueError("User Email Is Important")

email=self.normalize_email(email)

user=self.model(email=email, name=name)

user.set_password(password)

user.save(using=self._db)

return user



def create_superuser(self, email, name, password):

user=self.create_user(email, name, password)

user.is_superuser=True

user.save(using=self._db)

return user




class UserProfile(AbstractBaseUser, PermissionsMixin):

email=models.EmailField(max_length=255, unique=True)

name=models.CharField(max_length=255)

is_active=models.BooleanField(default=True)

is_staff=models.BooleanField(default=False)

objects=UserProfileManager()

USERNAME_FIELD="email"

REQUIRED_FIELDS=["name"]


def get_full_name(self):

return self.name


def short_name(self):

return self.name


def __str__(self):

return self.email



Note: Now you can delete, update and path anyones account try it before going forward

127.0.0.1:8000/api/profile/1 you will see all the option to edit and delete. However to control this and only authentic user can modify or delete its own profile we have to add authentications and permissions for that create a new file permissions.py in profiles_api

and write down the following code.


from rest_framework import permissions

class UpdateOwnProfile(permissions.BasePermission):

"""Allow user o edit their own permission"""

def has_object_permission(self, request, view, obj):

"""check user is trying to update their own profile"""

if request.method in permissions.SAFE_METHODS:

return True

return obj.id==request.user.id

"""if request.method contain GET request it will show all the profiles

means readable mode. if request.method contain editable request like PUT,PATCH,DELETE etc then it will check request.user.id === obj.id if both are same it will return true else false means not allow to perform put, PATCH kind of operation. you will not see the option their."""




90 views0 comments

Recent Posts

See All

1) Write a program whether a number is divisible by 7 and 9. 2) Write a program to check whether a number is Positive or Negative. 3) How many data types in Python programming? 4) What is the data typ

There are some questions you need to solve. Don't open your book and don't copy from another students. Write it in your own language or in English. What is standard deviation, and how is it used in pr

bottom of page