class CreateProjectWorkorderView(views.APIView):
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request, project_title):
        user = request.user
        try:
            project_sites = ProjectSiteModel.objects.filter(title=project_title)
        except Exception as e:
            return response.Response({"detail": "Project title not found"}, status=status.HTTP_404_NOT_FOUND)

        try:
            project_tickets = ProjectWorkorderModel.objects.filter(project_title=project_title)
            if project_tickets.exists():
                return response.Response({"detail": "Project tickets already exist"},
                                         status=status.HTTP_400_BAD_REQUEST)
        except Exception as e:
            return response.Response({"detail": "Error while filtering project ticket model"},
                                     status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        if project_sites.exists():
            data_list = project_sites.values_list('data', flat=True)
            cpg_data_list = project_sites.values_list('cpg_data', flat=True)

            work_orders_to_create = {
                'SA': [],
                'ROAD': [],
                'POWER': [],
                'TI': [],
                'CW': [],
            }

            for data, cpg_data in zip(data_list, cpg_data_list):
                data_dict = json.loads(data)
                cpg_data_dict = json.loads(cpg_data)

                for key in cpg_data_dict:
                    if key in data_dict:
                        data_dict[key] = cpg_data_dict[key]

                site_title = data_dict.get('Site ID')
                pm = data_dict.get('MTNI PM/PC')
                parent_work_order_id = create_parent_work_order_id(site_title, project_title)
                project_ticket = ProjectWorkorderModel.objects.create(
                    site_title=site_title,
                    status='pending',
                    created_by=user,
                    pm=pm,
                    work_order_id=parent_work_order_id,
                    project_title=project_title,
                    data=data_dict
                )

                contractors = {
                    'SA Contractor Name': 'SA',
                    'CW Contractor Name': 'CW',
                    'TI Contractor Name': 'TI',
                    'Road Contractor Name': 'ROAD',
                    'Power Contractor Name': 'POWER',
                }

                for contractor_type, domain in contractors.items():
                    contractor_name = data_dict.get(contractor_type)
                    company = None
                    extra_contractor = None

                    if contractor_name in ['TBD', 'NTBD']:
                        extra_contractor = contractor_name
                        if contractor_name == 'NTBD':
                            continue
                    else:
                        try:
                            company = Company.objects.get(name=contractor_name)
                        except Company.DoesNotExist:
                            return response.Response({"detail": f"Contractor name {contractor_name} not found"},
                                                     status=status.HTTP_404_NOT_FOUND)

                    work_order_id = create_contractor_work_order_id(domain, site_title, project_title)

                    work_order_model_class = {
                        'SA': SAWorkOrdersModel,
                        'CW': CWWorkOrdersModel,
                        'TI': TIWorkOrdersModel,
                        'ROAD': RoadWorkOrdersModel,
                        'POWER': PowerWorkOrdersModel,
                    }[domain]
                    if contractor_name == 'TBD':
                        wo_status = 'TBD'
                    else:
                        if domain == 'SA':
                            wo_status = 'pending'
                        else:
                            wo_status = 'locked'
                    work_orders_to_create[domain].append(
                        work_order_model_class(
                            parent_work_order=project_ticket,
                            work_order_id=work_order_id,
                            contractor=company,
                            extra_contractor=extra_contractor,
                            status=wo_status,
                            created_by=user
                        )
                    )

            for domain, work_orders in work_orders_to_create.items():
                if work_orders:
                    work_order_model_class = {
                        'SA': SAWorkOrdersModel,
                        'ROAD': RoadWorkOrdersModel,
                        'POWER': PowerWorkOrdersModel,
                        'TI': TIWorkOrdersModel,
                        'CW': CWWorkOrdersModel,
                    }[domain]

                    work_order_model_class.objects.bulk_create(work_orders)

            project_sites.update(status='Done')

            return response.Response({"detail": "Workorders created successfully"},
                                     status=status.HTTP_201_CREATED)
        else:
            return response.Response({"detail": "No project sites found for the given title"},
                                     status=status.HTTP_404_NOT_FOUND)

Consider above view. It works fine. Now i want to have another view to able create workorders for partially updated ProjectSiteModel instances.
I coded a portion of that view, you should now complete the v2 view based on the first view. For overall description you need to check cpg_data of projectsitemodel instance, if that field was blank or none it means you should skip, other wise you should check if the corresponding workorder of site id exists in ProjectWorkorderModel so again you need to skip them. Actually you should check all site ids in projectsitemodel instances with the corresponding site id in projectworkordermodel, if there are site id with filled cpg_data in projectsitemodel and not exists in projectworkordermodel you should create proper workorders.
class CreateProjectWorkorderV2View(views.APIView):
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request, project_title):
        user = request.user
        try:
            project_sites = ProjectSiteModel.objects.filter(title=project_title)
        except ProjectSiteModel.DoesNotExist:
            return response.Response({"detail": "No project sites found for the given title"},
                                     status=status.HTTP_404_NOT_FOUND)
        not_updated_site_ids = []
        for project_site in project_sites:
            if project_site.cpg_data == None:
                site_id = project_site.site_title
                not_updated_site_ids.append(site_id)

        try:
            workorders = ProjectWorkorderModel.objects.filter(project_title=project_title)
        except ProjectWorkorderModel.DoesNotExist as e:
            updated_site_ids=[]
            for project_site in project_sites:
                data=json.loads(project_site)
                existing_cpg_data=data.cpg_data
                if existing_cpg_data is not None:
                    instance_site_id=data.site_id
                    updated_site_ids.append(instance_site_id)
...

class ProjectWorkorderModel(models.Model):
    id = models.UUIDField(default=uuid.uuid4, primary_key=True, editable=False, unique=True)
    site_title = models.CharField(max_length=255, null=True, blank=True)
    work_order_id = models.CharField(max_length=255)
    # parent_ticket_id = models.CharField(max_length=255, null=True, blank=True)
    # type = models.CharField(max_length=255,null=True)  # cw,road,ti,...
    data = models.JSONField(null=True, blank=True)
    status = models.CharField(choices=WORK_ORDER_STATUS, default=[0][0], max_length=255)
    project_title = models.CharField(max_length=255, null=True, blank=True)
    pm = models.CharField(max_length=255, null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    created_by = models.ForeignKey(User, on_delete=models.DO_NOTHING)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ['-created_at']

    def __str__(self):
        return f'{self.work_order_id}'

class ProjectSiteModel(models.Model):
    PROJECT_STATUS = (
        ('pending', 'pending'),
        ('in-progress', 'in-progress'),
        ('Done', 'Done'),
        ('drafted', 'drafted'),
        ('return', 'returned'),
        ('partially_done','Partially Done')
    )
    PROJECT_TYPE = (
        ('new_site_rollout', 'new site rollout'),
        ('relocation', 'relocation'),
        ('modernization', 'modernization'),
        ('new_site_uso', 'new site uso'),
    )
    id = models.UUIDField(default=uuid.uuid4, primary_key=True)
    site_id = models.ForeignKey(Site, on_delete=models.CASCADE, null=True)
    site_title = models.CharField(max_length=50, null=True)
    status = models.CharField(choices=PROJECT_STATUS, default=PROJECT_STATUS[0][0])
    type = models.CharField(choices=PROJECT_TYPE)
    title = models.CharField(max_length=255)
    data = models.JSONField()
    cpg_data = models.JSONField(null=True)
    atoll_existence = models.BooleanField(default=True)
    created_date = models.DateTimeField(auto_now_add=True)
    updated_date = models.DateTimeField(auto_now=True)
    created_by = models.CharField(max_length=100)
    updated_by = models.CharField(max_length=100)
    temp_version = models.ForeignKey(ProjectSiteTemplateModel, on_delete=models.SET_NULL, null=True)

    class Meta:
        db_table = 'project_site'
        permissions = [
            ('can_upload_cpg_file', 'Can upload cpg file'),
            ('can_upload_project_file', 'Can upload project file'),
            ('can_download_project_file', 'Can download project file'),
            ('total_wo_show', 'Can view all workorders'),
            ('pm_wo_show', 'Can view all pm-associated workorders'),
            ('subcon_wo_show', 'Can view all subcon-associated workorders'),
        ]

    @classmethod
    def get_deduplicated_records(cls):
        latest_records = cls.objects.values('title').annotate(
            latest_created_date=Max('created_date')
        ).values('latest_created_date')
        result = cls.objects.filter(created_date__in=latest_records).order_by('-created_date')

        return result

Also when workorders created based on the complete wo or partially you should update status of all project instances in projectsitemodel. If all site ids have their workorders should be “Done” other wise should “partially_done”. It is possible that in a project that has a bunch of 10 site ids user first update 5 of them so after creation of workorder the status of project in projectsitemodel should be partially_done, in second turn it updates 2 then it should be partially_done and after that with a 3 site id updating when created the 10 workorders it should be updated to “Done”