Не удается вставить json-запрос в модель Django с внешними ключами
У меня есть таблица Main с некоторыми данными, включая внешние ключи к другим моделям. У меня возникла проблема с добавлением данных в эту модель из JSON запроса. Некоторые поля в запросе могут быть 'None', некоторые могут отсутствовать.
models.py
from django.db import models
class Systems(models.Model):
class Meta:
db_table = 'systems'
system = models.CharField(max_length=100, unique=True)
active = models.BooleanField(default=True)
def __str__(self):
return self.system
class Location(models.Model):
class Meta:
db_table = 'location'
location = models.CharField(max_length=100, unique=True)
active = models.BooleanField(default=True)
def __str__(self):
return self.location
class RepairPlace(models.Model):
class Meta:
db_table = 'repair_place'
place = models.CharField(max_length=100, unique=True)
active = models.BooleanField(default=True)
def __str__(self):
return self.place
class Equipments(models.Model):
class Meta:
db_table = 'equipments'
equipment = models.CharField(max_length=100, unique=True)
equipment_system = models.ForeignKey(Systems, on_delete=models.RESTRICT)
active = models.BooleanField(default=True)
def __str__(self):
return self.equipment
class Employees(models.Model):
class Meta:
db_table = 'employees'
unique_together = ('last_name', 'first_name', 'middle_name')
last_name = models.CharField(max_length=100)
first_name = models.CharField(max_length=100)
middle_name = models.CharField(max_length=100, null=True, blank=True)
organization = models.CharField(max_length=100, null=True, blank=True)
active = models.BooleanField(default=True)
def __str__(self):
result = self.last_name + ' ' + self.first_name + ' ' + self.middle_name
return result
class Main(models.Model):
class Meta:
db_table = 'main'
object = models.ForeignKey(Location, on_delete=models.RESTRICT, related_name="location_name"')
name = models.ForeignKey(Equipments, on_delete=models.RESTRICT, related_name="equipment_name")
serial = models.CharField(max_length=100, null=True, blank=True)
system = models.ForeignKey(Systems, on_delete=models.RESTRICT, related_name="system_name")
accepted_dt = models.DateField(null=True, blank=True)
shipped_repair_dt = models.DateField(null=True, blank=True)
accepted_repair_dt = models.DateField(null=True, blank=True)
issued_object = models.ForeignKey(Location, on_delete=models.RESTRICT, related_name='issued_location_name', null=True, blank=True)
serial2 = models.CharField(max_length=100, null=True, blank=True)
issued_dt = models.DateField(null=True, blank=True)
repair_place = models.ForeignKey(RepairPlace, on_delete=models.RESTRICT, related_name="repair_name", null=True, blank=True)
comments = models.TextField(max_length=500, null=True, blank=True)
responsible_employee = models.ForeignKey(Employees, on_delete=models.RESTRICT, related_name="employee_name", null=True, blank=True)
logistic_serializers.py
class SystemsSerializer(serializers.ModelSerializer):
class Meta:
model = models.Systems
fields = '__all__'
class LocationSerializer(serializers.ModelSerializer):
class Meta:
model = models.Location
fields = '__all__'
class RepairPlaceSerializer(serializers.ModelSerializer):
class Meta:
model = models.RepairPlace
fields = '__all__'
class EquipmentsSerializer(serializers.ModelSerializer):
class Meta:
model = models.Equipments
depth = 1
fields = '__all__'
class EmployeesSerializer(serializers.ModelSerializer):
class Meta:
model = models.Employees
fields = '__all__'
class MainSerializer(serializers.ModelSerializer):
class Meta:
model = models.Main
depth = 1
fields = ("id", "serial", "accepted_dt", "shipped_repair_dt", "accepted_repair_dt",
"serial2", "issued_dt", "comments", "object", "name", "system", "issued_object",
"repair_place", "responsible_employee")
class MainSerializerPost(serializers.ModelSerializer):
name = EquipmentsSerializer()
system = SystemsSerializer()
issued_object = LocationSerializer()
object = LocationSerializer()
repair_place = RepairPlaceSerializer()
responsible_employee = EmployeesSerializer()
class Meta:
model = models.Main
depth = 1
#fields = "__all__"
fields = ("serial", "accepted_dt", "shipped_repair_dt", "accepted_repair_dt",
"serial2", "issued_dt", "comments", "object", "name", "system", "issued_object",
"repair_place", "responsible_employee")
views.py
from .models import Main, Location, Systems, Equipments, RepairPlace, Employees
from . import logistic_serializers
from rest_framework.response import Response
from rest_framework.views import APIView
class MainView_1(APIView):
def post(self, request):
print(request.data)
serializer = logistic_serializers.MainSerializerPost(data=request.data)
if serializer.is_valid():
print(serializer.validated_data)
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
print('Serializer is invalid')
print(serializer.errors)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class MainView_2(APIView):
def post(self, request):
print(request.data)
serializer = logistic_serializers.MainSerializer(data=request.data)
if serializer.is_valid():
print(serializer.validated_data)
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
print('Serializer is invalid')
print(serializer.errors)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class MainView_3(APIView):
def post(self, request):
arguments = {}
fields = ['serial', 'serial2', 'comments', 'accepted_dt',
'shipped_repair_dt', 'accepted_repair_dt', 'issued_dt']
fk_fields = ['object', 'name', 'system', 'issued_object',
'repair_place', 'responsible_employee']
for field in fields:
print(request.data.get(field))
if request.data.get(field):
arguments[field] = request.data.get(field)
for field in fk_fields:
try:
if request.data.get(field).get("id"):
arguments[field+'_id'] = request.data.get(field).get("id")
except:
pass
print(arguments)
query = Main.objects.create(**arguments)
try:
query.save()
return Response(status=status.HTTP_201_CREATED)
except:
return Response(query.errors, status=status.HTTP_400_BAD_REQUEST)
Из фронтенда я получаю запрос следующего вида - {"serial": "346", "accepted_dt": "2022-04-19", "serial2": "null", "comments": 0, "object": { "id": 61, "location": "test", "active": "True"}, "name": { "id": 2, "equipment": "SI3000", "active": "True", "equipment_system": { "id": 1, "system": "SI2000", "active": "True"}}, "system": { "id": 9, "system": "112", "active": "True"}}, "issued_object": "None", "repair_place": "Нет", "ответственный_сотрудник": "Нет"}
Я перепробовал множество вариантов.
Если я использую MainView_1, он возвращает:
Serializer is invalid
{'object': {'location': [ErrorDetail(string='Location with this location already exists.', code='unique')]}, 'name': {'equipment': [ErrorDetail(string='Equipment with this equipment already exists.', code='unique')]}, 'system': {'system': [ErrorDetail(string='Systems with this system already exists.', code='unique')]}, 'issued_object': {'non_field_errors': [ErrorDetail(string='Invalid data. Expected a dictionary, but got str.', code='invalid')]}, 'repair_place': {'non_field_errors': [ErrorDetail(string='Invalid data. Expected a dictionary, but got str.', code='invalid')]}, 'responsible_employee': {'non_field_errors': [ErrorDetail(string='Invalid data. Expected a dictionary, but got str.', code='invalid')]}}
Похоже, что он пытается проверить связанные модели для записи в них, но мне не нужно ничего вставлять в связанные модели. Я просто хочу записать ID связанных объектов.
Если я использую MainView_2, он возвращает:
serialized.validated_data - OrderedDict([('serial', '346'), ('accepted_dt', datetime.date(2022, 4, 19)), ('serial2', 'null'), ('comments', '0')])
and error - django.db.utils.IntegrityError: null value in column "name_id" of relation "main" violates not-null constraint
DETAIL: Failing row contains (50, 346, 2022-04-19, null, null, null, null, 0, null, null, null, null, null, null).
Похоже, что он не может сериализовать данные из объектов с внешним ключом.
Я решил эту проблему ручным разбором в MainView_3
Это работает, но я думаю, что это не очень хорошее решение.
Если кто-то знает, как решить мою проблему с помощью сериализаторов, я буду благодарен.