Django-DRF-M2M Object Multiple Selection Nested Serializer -Tutorial01

admin
By -
0

In this we are going to learn how can we select existing objects in drf when we using post method or create objects using drf api.


Step 01: Project Initiated

Create new django project using shell

Command: 

django-admin startproject maintain_proj

e.g .

PS:> django-admin startproject myproject 


now we going to our created project root dir using our current shell 

with this command

Command:

cd maintain_proj

e.g. 

PS:> cd myproject 


and we are going to install drf to our project and setup it.

Command:

pip install django-rest-framework

e.g. 

PS:> cd myproject 

now going to settings.py file for your root project in out case its

maintain_proj/

maintain_proj/

settings.py

Inside this file we are going to configure our drf here with basic setup none auth right now we setup auth in last. 


Step02: Make webapps

Now we are going to create new webapp name "core" inside our "maintain_proj" djangoproject using our shell.

Command:

python -m startapp core

e.g. 

PS:> python -m startapp core

or


django-admin startapp core

e.g. 

PS:> django-admin startapp core


Step03: Create Models inside "core"

maintain_proj/

core/

models.py

Code:

from django.contrib.auth.models import User

import uuid


class Project(models.Model):

    project_id = models.CharField(max_length=255, default=uuid.uuid4().hex[:12], editable=False)

    project_name = models.CharField(max_length=50,blank=False)

    description =  models.TextField(blank=False,max_length=540)

    started_at = models.DateField(blank=True,null=True)

    end_at = models.DateField(blank=True,null=True)

    created_at = models.DateTimeField(blank=True,auto_now_add=True)

    #auto_now_add for automatic add firsttime when it object created so it not change even how many time we 

    updated_at = models.DateTimeField(blank=True,auto_now=True)

    #auto_now is for whenever this we chnage anything in object it will update the date time and store it to updated_at

    def __str__(self):

        return f"{self.project_name},{self.project_id}"

    

class TimeSheet(models.Model):

    user = models.ForeignKey(User,on_delete=models.CASCADE)

    projects = models.ManyToManyField(Project,blank=True)

    week_start_date = models.DateField(blank=True,null=True)

    hours_worked = models.DecimalField(max_digits=5, decimal_places=2)


    def __str__(self):

        return f"{self.id}{self.user.username}"


We are here going to create two models and we are selection multiple objects from models1 to and connect them to new object of model2 object using m2m manytomanyfield.



e.g.

class Model_1(models.Model):

 ......

#M2M Fields Models:

class Model_2(models.Model):

  field_name = ManytoManyField(Model1)

...........


Step04: Making API ENDPOINTS and Serializer,Views

Create new "api" folder/dir inside project root directory .

Inside the maintain_proj 

maintain_proj/

api/


Inside this "api"  first create a init file - __init__.py

4.1 : Now create new "serializers.py" file

Open this file and put this code on this file.


from rest_framework import serializers

from core.models import Project , TimeSheet

class ProjectSerializer(serializers.ModelSerializer):

    class Meta:

        model = Project

        fields = "__all__"

 

class TimeSheetSerializer(serializers.ModelSerializer):

    projects = ProjectSerializer(many=True)

    class Meta:

        model = TimeSheet

        fields = ['id','projects','user','week_start_date','hours_worked']

       

4.2: Now create "views.py" file and put this code on that






from rest_framework import generics

from core.models import Project, TimeSheet

from .serializers import ProjectSerializer,TimeSheetSerializer

from django.contrib.auth.models import User

from rest_framework import mixins

#Retrieving a list of timesheet entries for a specific user

#Ensure that users can only view and edit their own timesheet entries.

from rest_framework.views import APIView

from rest_framework.response import Response


class TimeSheetCreateView(generics.ListAPIView,mixins.CreateModelMixin):

    queryset = TimeSheet.objects.all()

    serializer_class = TimeSheetSerializer


    def get_queryset(self):

        user = self.request.user

        if user.is_authenticated:

            return TimeSheet.objects.filter(user=user)

        else:

            return TimeSheet.objects.none()

            

    def post(self, request, *args, **kwargs):

        data = request.data

        projects= request.data.get("projects")

        user = request.user

        week_start_date = request.data.get("week_start_date")

        hours_worked = request.data.get("hours_worked")

        time_sheet = TimeSheet.objects.create(user=user, week_start_date=week_start_date, hours_worked=hours_worked)


         # Link TimeSheet with Projects

        for project_id in projects:

            try:

                project = Project.objects.get(pk=project_id)

                time_sheet.projects.add(project)

            except Project.DoesNotExist:

                raise serializers.ValidationError({"projects": f"Project with ID {project_id} not found."})

        # Serialize and return created TimeSheet

        serializer = TimeSheetSerializer(time_sheet)

        return Response(serializer.data)


class TimeSheetListView(generics.ListAPIView):

    queryset = TimeSheet.objects.all()

    serializer_class = TimeSheetSerializer


    def get_queryset(self):

        user = self.request.user

        if user.is_authenticated:

            return TimeSheet.objects.filter(user=user)

        else:

            return TimeSheet.objects.none()

    


class TimeSheetDetailView(generics.RetrieveAPIView,mixins.UpdateModelMixin,):

    queryset = TimeSheet.objects.all()

    serializer_class = TimeSheetSerializer

    

    def get_queryset(self):

        user = self.request.user

        if user.is_authenticated:

            return TimeSheet.objects.filter(user=user)

        else:

            return TimeSheet.objects.none()

    

    def put(self, request, pk, *args, **kwargs):

        try:

            time_sheet = TimeSheet.objects.get(pk=pk)

        except TimeSheet.DoesNotExist:

            return Response({"error": "TimeSheet not found."}, status=status.HTTP_404_NOT_FOUND)

            # Update user, week_start_date, and hours_worked if provided

        data = request.data

        if data.get("user"):

            # time_sheet.user = data["user"]

            time_sheet.user = request.user

           

        if data.get("week_start_date"):

            time_sheet.week_start_date = data["week_start_date"]

        if data.get("hours_worked"):

            time_sheet.hours_worked = data["hours_worked"]

            # Update projects

        projects = data.get("projects")

        if projects is not None:

             # Clear existing projects

            time_sheet.projects.clear()

            # Link provided projects

            for project_id in projects:

                try:

                    project = Project.objects.get(pk=project_id)

                    time_sheet.projects.add(project)

                except Project.DoesNotExist:

                    return Response({"projects": f"Project with ID {project_id} not found."}, status=status.HTTP_400_BAD_REQUEST)

                    # Save the updated TimeSheet

        time_sheet.save()

        serializer = TimeSheetSerializer(time_sheet)

        return Response(serializer.data)

 

4.3: Now create new file name "urls.py"

Put this code on that

from django.urls import path

from . import views

app_name = 'api'

urlpatterns = [

 path('timesheets/lists/',views.TimeSheetListView.as_view(),name='timesheet_list'),

 path('timesheets/<pk>/update/',views.TimeSheetDetailView.as_view(),name='timesheet_detail'),

 path('timesheets/create',views.TimeSheetCreateView.as_view(),name='timesheet_create_entry'),

]

 




  • Best practices for managing nested M2M data in Django

Post a Comment

0Comments

Put Your Thought or Query Here

Post a Comment (0)