【问题标题】:Django: IntegrityError null value violates not-null constraintDjango:IntegrityError 空值违反非空约束
【发布时间】:2020-08-04 23:23:19
【问题描述】:

在我的 django 应用程序中,发生了一些奇怪的事情,我不明白。

我有两个不同的表(employeeProfilepurchaserShippingDetail),每个表都有一个与 OneToOneField 关系的字段,但第一个表(employeeProfile) 在使用 OneToOneField 的字段 user 中,我可以使用 api 传递字符串表示,例如 Michael 并且我没有收到错误,但在我的第二个表中具有类似的结构当我添加一个字符串表示时,我得到了

IntegrityError at /api/clients/shipping/ “owner_id”列中的空值违反非空约束

第一个表模型(工作正常)


class employeeProfile(models.Model):
    image = models.ImageField(default='default.png',upload_to='employee_photos/%Y/%m/%d/')
    user = models.OneToOneField(CustomUser, on_delete=models.CASCADE, related_name="employee_profile")
    phone_no = models.CharField(max_length=10, unique=True)

    def __str__(self):
        return self.user.name

第二个表模型(抛出“owner_id”的那个违反了非空约束错误

class purchaserShippingDetail(models.Model):

    frequent_customer = models.BooleanField(default=False)
    owner = models.OneToOneField(Purchaser, on_delete=models.CASCADE, related_name="purchaser_shipping")
    address = models.CharField(max_length=12, blank=True)
    zip_code = models.CharField(max_length=12, blank=True)
    location = models.CharField(max_length=255)

    def __str__(self):
        return self.owner.name

购买者型号

class Purchaser(models.Model):
    name = models.CharField(max_length=50)
    phone = models.CharField(max_length=20, unique=True)
    email = models.EmailField(max_length=255, unique=True, blank=True)
    data_added = models.DateField(default=datetime.date.today)

    def __str__(self):
        return self.name

purchaserShippingDetail 模型的序列化器

class purchaserShippingDetailSerializer(serializers.ModelSerializer):
    owner = serializers.StringRelatedField(read_only=True)
    class Meta:
        model = purchaserShippingDetail
        fields = '__all__'

Views.py for purchaserShippingDetail 模型

class purchaserShippingDetailsListCreateView(ListCreateAPIView):

    serializer_class = purchaserShippingDetailSerializer
    queryset = purchaserShippingDetail.objects.all()

编辑:添加了购买者模型表

【问题讨论】:

  • 如果 owner 可以为 null 设置 owner = models.OneToOneField(Purchaser, on_delete=models.CASCADE, related_name=purchaser_shipping, blank=True, null=True) 否则您可能在发出请求时忘记传递 owner_id(整数)。
  • 设置为 null 后,请求被传递,但不是使用提供的名称,例如 Michael,而是使用 null。关于您的第二点,我试图避免传递 owner_id,因为在前端,有人可能不知道所有购买者的所有 owner_id,而是他们想使用购买者的姓名
  • 我认为您必须通过 owner_id,这就是一个 purchaseShippingDetail 表识别您的 Purchaser 表的方式。我的意思是主键是 id 不是所有者名称。在您的情况下,您可以将所有者名称设置为 pk 我猜,但它必须是唯一的。 PS:在命名你的类时使用 UpperCamelCase 约定以获得良好的实践。

标签: django api django-models django-rest-framework django-serializer


【解决方案1】:

能否请您也发布Purchaser 模型?有一个引用字段owner_id,我们在您的帖子中看不到,这将解释更多。

您是否在最近的迁移中添加了所有者字段?可能是您将不可为空的字段添加到具有现有行的表中,使这些行无法满足不可为空的条件。

您不能在 OneToOneField 上添加默认值,因此在这种情况下,您必须首先将该字段添加为 null=True。 然后创建一个空的迁移文件来实例化该表上的所有行,因此没有行具有空值。通常您通过manage.py makemigrations app_name --empty 执行此操作。

该文件可能类似于

from django.db import migrations

def instantiate_owner(apps, schema_editor):
    purchaserShippingDetail = apps.get_model("appname", "purchaserShippingDetail")
    Purchaser = apps.get_model("some_other_app", "Purchaser")

    for detail in purchaserShippingDetail.objects.all():
      owner = Purchaser.objects.get(some_unique_criteria=detail.unique_criteria)
      detail.owner = owner
      detail.save()


class Migration(migrations.Migration):

    dependencies = [
       ...,
    ]

    operations = [
        migrations.RunPython(instantiate_owner),
    ]

完成后,您可以删除模型中的 null=True 并进行另一次迁移。

【讨论】:

  • 抱歉,我已更新代码以包含模型。另外,我没有任何owner_id 字段,只有具有OneToOneField 的owner。我假设 postgres 自动添加 owner_id 字段
  • 你可以试试owner = serializers.StringRelatedField(source='owner.name', read_only=True) 如果不行,你能不能把api应用的迁移文件贴出来。
  • 它没有用。我正在考虑通过添加 def perform_create(self, serializer): serializer.instance.owner_id = self.kwargs.get('pk') serializer.save() 来更改我的 views.py 但我遇到的问题是获取 Purchaser 的实例
  • 我不知道您为什么要避免谈论迁移文件。了解您添加字段和表格行的顺序对我们很重要。如果您在 Purchaser 之后添加了 purchaserShippingDetail 模型,则无法满足非空约束。解决方案在我原来的答案中。如果您的序列化程序是问题,它会给您ValidationError,而不是IntegrityError
  • 我创建了一个新应用程序(没有进行任何迁移),我订购模型的方式是第一个 Purchaser 模型,然后是 purchaserShippingDetail,设置在完成我进行迁移的所有内容后启动序列化程序。因此错误。
猜你喜欢
  • 2021-11-02
  • 1970-01-01
  • 2016-02-14
  • 2017-02-18
  • 2020-08-12
  • 1970-01-01
  • 1970-01-01
  • 2013-06-23
  • 2012-11-01
相关资源
最近更新 更多