Django.db.utils.IntegrityError: нулевое значение в столбце отношения нарушает ограничение not-null
Я пытаюсь добавить несколько существующих объектов объектов к объекту ведущего всякий раз, когда создаю новый объект ведущего с помощью сериализатора json-полей. Когда я вывожу "assigned_facilities_id", он возвращает: "none", но он есть в json-данных, которые я отправляю в сериализатор. Кто-нибудь знает, почему это происходит? Вот ошибка, которую я получаю, когда пытаюсь создать лид:
django.db.utils.IntegrityError: null value in column "assigned_facilities_id" of relation "users_leadfacilityassign" violates not-null constraint
DETAIL: Failing row contains (78, null, null, 159).
File "/app/users/api/views.py", line 53, in perform_create
serializer.save(agent=self.request.user)
File "/usr/local/lib/python3.9/site-packages/rest_framework/serializers.py", line 205, in save
self.instance = self.create(validated_data)
File "/app/users/api/serializers.py", line 252, in create
instance.leadfacility.create(assigned_facilities_id=assigned_facilities.get('facility_id'), datetime=assigned_facilities.get('datetime'))
class LeadUpdateSerializer(serializers.ModelSerializer):
is_owner = serializers.SerializerMethodField()
assigned_facilities = serializers.JSONField(required=False, allow_null=True, write_only=True)
class Meta:
model = Lead
fields = (
"id",
"first_name",
"last_name",
"is_owner",
"assigned_facilities",
)
read_only_fields = ("id", "is_owner")
def get_is_owner(self, obj):
user = self.context["request"].user
return obj.agent == user
def create(self, validated_data):
assigned_facilities = validated_data.pop("assigned_facilities")
instance = Lead.objects.create(**validated_data)
for item in assigned_facilities:
instance.leadfacility.create(assigned_facilities_id=assigned_facilities.get('facility_id'), datetime=assigned_facilities.get('datetime'))
return instance
json
{
"assigned_facilities": [{
"facility_id": "1",
"datetime": "2018-12-19 09:26:03.478039"
},
{
"facility_id": "1",
"datetime": "2019-12-19 08:26:03.478039"
}
]
}
models.py
class Facility(models.Model):
name = models.CharField(max_length=150, null=True, blank=False)
def __str__(self):
return self.name
class Lead(models.Model):
first_name = models.CharField(max_length=40, null=True, blank=True)
last_name = models.CharField(max_length=40, null=True, blank=True)
def __str__(self):
return f"{self.first_name} {self.last_name}"
class LeadFacilityAssign(models.Model):
assigned_facilities = models.ForeignKey(Facility, on_delete=models.CASCADE, related_name='leadfacility')
lead = models.ForeignKey(Lead, on_delete=models.CASCADE, related_name='leadfacility')
datetime = models.DateTimeField()
views.py
class LeadCreateView(CreateAPIView):
permission_classes = [IsAuthenticated, IsLeadOwner]
serializer_class = LeadUpdateSerializer
def perform_create(self, serializer):
serializer.save(agent=self.request.user)
вы делаете :
for item in assigned_facilities:
instance.leadfacility.create(assigned_facilities_id=assigned_facilities.get('facility_id'), datetime=assigned_facilities.get('datetime'))
но нигде не используется.
for item in assigned_facilities:
instance.leadfacility.create(assigned_facilities_id=item['facility_id'], datetime=item['datetime'])
Когда вы используете 'pop', он получает, а затем удаляет данные. Поэтому вы не можете обработать их в цикле for. Используйте get вместо pop, и ваша проблема будет решена.
assigned_facilities = validated_data.pop("assigned_facilities")
change this line to
assigned_facilities = validated_data.get("assigned_facilities")
Я бы предложил другой, возможно, лучший подход. Вместо JSONField
используйте вложенный сериализатор моделей.
class AssignedFacilitySerializer(serializers.ModelSerializer):
fields = ('assigned_facilities_id', 'datetime')
model = Facility
class LeadUpdateSerializer(serializers.ModelSerializer):
assigned_facilities = AssignedFacilitySerializer(many=True)
def create(self, validated_data):
assigned_facilities = validated_data.pop("assigned_facilities")
instance = Lead.objects.create(**validated_data)
for item in assigned_facilities:
instance.leadfacility.create(**item)
return instance
Вы не опубликовали свою модель Facility
, поэтому могут быть неправильно названные поля, возможно related_name
тоже (leadfacility
).
Я вижу несколько проблем как в ваших моделях, так и в том, как вы добавляете объекты к свинцу в вашем цикле.
Пожалуйста, посмотрите на https://docs.djangoproject.com/en/4.1/topics/db/models/#extra-fields-on-many-to-many-relationships и отредактируйте свои модели соответствующим образом.
TL;DR
Затем вы можете поместить дополнительные поля в промежуточную модель.
Это LeadFacilityAssign
в вашем случае.
Промежуточная модель ассоциируется с ManyToManyField
с помощью аргумента through
, указывающего на модель, которая будет действовать как промежуточная.
Вам не хватает этой части. Обязательно добавьте ManyToManyField
к Leads
.
Если вы продолжите читать документацию, вы также обнаружите, что можно использовать add()
, create()
или set()
для создания отношений между Lead
и Facility
с помощью сквозной модели.
Вы упомянули, что объекты уже существуют, поэтому create()
- неправильный метод.
Пожалуйста, используйте add()
или set()
в соответствии с вашим сценарием использования и предварительно найдите эти объекты, используя их идентификатор.