Philip Mutua
Philip Mutua

Reputation: 6891

How do create an object that has multiple objects in django rest framework via a POST method using class based views

I have created an Employee class below in my models. The Employee class has multiple Foreign Keys such as User,Contact,Skill etc. I would like to make it possible that when I create an Employee all the other objects will be created plus including the User object. I have implemented a POST method in my view that does this but I feel like my code is too long. How do I make a single POST to create all these multiple objects? An illustration using Managers will be also nice.

class Employee(models.Model):
    """
    Model, which holds general information of an employee.

    """
    user = models.OneToOneField(settings.AUTH_USER_MODEL,
                                related_name='employees', null=True)

    company = models.ForeignKey(
        'hr.Company',
        verbose_name='Company',
        related_name='companies',
        null=True, blank=True,
    )
    hr_number = models.CharField(
        verbose_name='HR number',
        blank=True, null=True,
        max_length=20, unique=True
    )
    identification_number = models.CharField(
        verbose_name='ID Number',
        blank=True, null=True,
        max_length=20, unique=True
    )
    contract_type = models.ForeignKey(Contract)
    tax_id_number = models.CharField(
        max_length=20, null=True, verbose_name='Tax ID', blank=True, unique=True)
    skill = models.ForeignKey(Skill)
    # joining can be added in user  profile
    joining_date = models.DateField(null=True, verbose_name="Joining Date")
    job_title = models.ForeignKey(
        Job, related_name='job_titles', null=True, blank=True, help_text='Default Permission for different modules in Portal depends upon employee\'s Designation.')
    department = models.ForeignKey(
        Department, related_name='department', null=True, blank=True, on_delete=models.SET_NULL)
    is_manager = models.BooleanField(default=False)
    # leave_count = models.IntegerField(default=0)
    active = models.BooleanField(default=True)

In my views I have have implemented the POST method below:

class AddEmployee(APIView):
    # permission_classes = (permissions.DjangoObjectPermissions,)
    # serializer_class = EmployeeSerializer
    """
{
    "user":null,
    "new_user":{
    "first_name":"John",
    "last_name":"Wane",
    "username":"Wai",
    "email":"[email protected]",
    "password":"123"
    },
    "company":1,
    "department":1,
    "identification_number":"234567",
    "hr_number":"GH/099/2017",
    "tax_id_number":"AEEEEEE",
    "joining_date":"2018-04-02",
    "job_title":null,
    "new_job":{
        "name":"Doctor",
        "min_salary":50000,
        "max_salary":50000

    }
}
    """

    def post(self, request, format=None):
        try:
            company = Company.objects.get(id=request.data['company'])

            department = Department.objects.get(id=request.data['department'])
            try:
                c_user = User.objects.get(id=request.data['user'])
            except:
                new_user = request.data['new_user']
                c_user = User.objects.create(first_name=new_user['first_name'],
                                             last_name=new_user['last_name'],
                                             username=new_user['username'],
                                             email=new_user['email'],
                                             password=new_user['password'])
            try:
                job_title = Job.objects.get(id=request.data['job_title'])
            except:
                new_job = request.data['new_job']
            if new_job:
                job_title = Job.objects.create(
                    name=new_job['name'],
                    min_salary=new_job['min_salary'],
                    max_salary=new_job['max_salary']
                )

            employee = Employee.objects.create(
                user=c_user,
                company=company,
                department=department,
                job_title=job_title,
                hr_number=request.data['hr_number'],
                identification_number=request.data['identification_number'],
                tax_id_number=request.data['tax_id_number'],
                joining_date=request.data['joining_date']

            )
        except Exception as e:
            print(e)
        return Response(status=status.HTTP_201_CREATED)

Upvotes: 2

Views: 129

Answers (1)

jmny
jmny

Reputation: 308

DRF do not manage nested serialiser or this kind of things. that said, you can simplify your code using Model.objects.get_or_create

example :

try:
   job_title = Job.objects.get(id=request.data['job_title'])
except:
   new_job = request.data['new_job']
if new_job:
   job_title = Job.objects.create(
       name=new_job['name'],
       min_salary=new_job['min_salary'],
       max_salary=new_job['max_salary']
   )

# can be write with get_or_create:
job_defaults = {
    'name': new_job['name'],
    'min_salary': new_job['min_salary'],
    'max_salary': new_job['max_salary'] 
}
Job.objects.get_or_create(name=new_job['name'],defaults=job_defaults)

You can also use Model Serializer to manage filtering + validating + save sub object

examples :

# serializers.py

class JobSerializer(serializers.ModelSerializer):
    class Meta:
        model = Job
        fields = ('id', 'name', 'min_salary', 'max_salary')

# inside views.py's  post method

try:
   job_title = Job.objects.get(id=request.data['job_title'])
except:
   JobSerializer(data=new_job).save()

see also:

Upvotes: 1

Related Questions