问题
After many years I code with Java, I got an interesting project at work to be developed using python django rest framework.
I have a complex model, with many relations, in which I want to create entities in DB based on one JSON request. Please refer to attached screenshot of my DB model.
My goal is to create new projects in the DB where I have set of companies in DB and a freelancer can suggest to a project of the company.
I would like to get a JSON request that contains:
- company id (ALREADY IN DB)
- Freelance: email, name, etc...
- Project info: name, year, description -> this will be newly created, unless the name already exists in the DB
- List of Tasks
- List of Requests
When I get the request on the server, I would like to check first if the freelancer exists (I lookup by email) then use his ID or create a new freelancer entity, then create a new Project entry (I can also check that I don't have duplicate by name and year - in such case throw an error) and create new tasks for the project with the relevant FK and same for Requests.
My experience with JEE, I would simply create a DTO that reflects the JSON and will just have a service layer that checks the condition and creates accordingly the objects.
I am a bit lost how to do it with django, all tutorials I see provide very clear way how to do simple CRUD operations for a DB model that is mapped almost 1 to 1 to the JSON (DTO), there is almost no business logic there.
Could someone please let me know how to get around this? maybe you have any good example you can refer?
Thank you.
回答1:
The individual serializers are used for field validation, so that there is no malicious data.
from django.db import transaction
from rest_framework import serializers
class FreeLancerSerializer(serializers.ModelSerializer):
class Meta(object):
model = FreeLancer
fields = ('email', '...other field')
class TasksSerializer(serializers.ModelSerializer):
class Meta(object):
model = Task
fields = (..task model fields..)
class RequestsSerializer(serializers.ModelSerializer):
class Meta(object):
model = Request
fields = (..request model fields..)
class ProjectSerializer(serializers.ModelSerializer):
freelancer = FreeLancerSerializer()
tasks = TasksSerializer(many=True)
requests = RequestsSerializer(many=True)
class Meta(object):
model = Project
fields = ('project_name', ..project model fields .., 'freelancer', 'tasks', 'requests')
#project_name validation
def validate_project_name(self, project_name):
if Project.objects.filter(project_name=project_name).exists():
raise serializers.ValidationError("project with this name already exists.")
return project_name
@transaction.atomic #will rollback all the transactions if something fails
def create(self, validated_data):
freelancer = validated_data.pop('freelancer')
tasks_data = validated_data.pop('tasks')
requests_data = validated_data.pop('requests')
# gets the freelancer if alread created else creates it.
freelancer_obj = FreeLancer.objects.get_or_create(
email = freelancer.get('email'),
defaults = freelancer
)
validated_data['freelancer'] = freelancer_obj
project = super(ProjectSerializer, self).create(validated_data)
#Validates tasks data and creates tasks
try:
task_objects = TasksSerializer(data=tasks_data, many=True)
task_objects.is_valid(raise_exception=True)
tasks = task_objects.save()
project.tasks.add(tasks); #add tasks to project.
except:
raise serializers.ValidationError("tasks not valid.")
#Validates requests data and creates requests
try:
request_objects = RequestsSerializer(data=requests_data, many=True)
request_objects.is_valid(raise_exception=True)
requests = request_objects.save()
project.requests.add(requests); #add requests to project.
except:
raise serializers.ValidationError("requests not valid.")
project.save()
return project
Note : Model level validations will also be needed like email
has to be unique
for freelancer and name
has to be unique
project model respectively and so on.
PS : there might be some changes you might need to to do.
来源:https://stackoverflow.com/questions/57599499/non-trivial-django-serializer-for-a-complex-model