Reputation: 4954
I am currently working on an API view, for a Job Planning system. Each Job
, has a single JobPlan
(which has a start and end date) and each JobPlan
, may have several JobPlanManagers
, users assigned to manage said Job
. User one might be in charge of one month, and User two might overlap User 1, but extend the job by a couple of weeks. Thus, when User 2 POSTS their new JobPlanManager
instance, they need to either create a new JobPlan (if no plan yet exists) or update the existing JobPlan
, to extend the start and end appropriately. The user's POST data would include their user ID, the Job ID, and a start and end date, something like:
{
"manager": (User ID),
"job_plan": {
"id": null,
"job": {
"id": (existing Job ID)
},
"start": "2018-02-01",
"end": "2018-02-28"
}
}
Additionally, I would like the return of this POST call to include all fields for JobPlan and Job, nested: e.g.:
{
"id": (created JobPlanManager instance ID)
"manager": (User ID),
"job_plan": {
"id": (New or existing JobPlan ID)
"job": {
"id": (Existing Job ID),
"name": "Existing Job Name"
}
"start": "2018-01-02",
"end": "2018-02-28"
}
}
My models look like:
class Job(models.Model)
name = models.CharField()
class JobPlan(models.Model):
job = models.ForeignKey(Job, unique=True)
start = models.DateField()
end = models.DateField()
class JobPlanManager(models.Model):
job_plan = models.ForeignKey(JobPlan)
manager = models.ForeignKey(User)
is_open = models.Boolean(default=False)
delta = models.IntegerField()
For my serializers, I am doing this in separate calls (e.g.- first create/update a JobPlan
, then pass the returned id along with the user ID to create my new JobPlanManager
), and they look like this:
class JobSerializer(serializers.ModelSerializer):
class Meta:
model = Job
fields = ('id', 'name',)
read_only_fields('id')
class JobPlanSerializer(serializers.ModelSerializer):
job = JobSerializer(many=False)
class Meta:
model = JobPlan
fields = ('id', 'job', 'start', 'end',)
read_only_fields('id')
def create(self, validated_data):
i_job = validated_data.get('job', None)
start = validated_data.get('start', None)
end = validated_data.get('end', None)
if JobPlan.objects.filter(job=i_job).exists():
jobplan = JobPlan.objects.get(job=i_job)
jobplan.start = min(jobplan.start, start)
jobplan.end = max(jobplan.end, end)
jobplan.save()
else:
jobplan = JobPlan.objects.create(job=i_job, start=start, end=end)
return jobplan
class JobPlanManagerSerializer(serializers.ModelSerializer):
job_plan = JobPlanSerializer(many=False)
class Meta:
model = JobPlanManager
fields = ('job_plan', 'manager', 'is_open', 'delta',)
read_only_fields('id')
Does anyone know of a way, that I can do this all in one call (as described above) and get the return described above from said call?
Upvotes: 1
Views: 320
Reputation: 3815
I use this trick to make it work:
class JobPlanSerializer(serializers.ModelSerializer):
job = PrimaryKeyRelatedField()
class Meta:
...
def create(self, validated_data):
...
def to_representation(self, instance):
ret = super().to_representation(instance)
ret['job'] = JobSerializer(context=self.context).to_representation(instance.job)
return ret
When posting data just send "job": (Existing Job ID)
instead of
"job": {"id": (existing Job ID)}
Upvotes: 1