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() в соответствии с вашим сценарием использования и предварительно найдите эти объекты, используя их идентификатор.

Вернуться на верх