Python Django Rest Framework复制键值在使用UserProfile创建信号时违反了唯一约束

Python Django Rest Framework复制键值在使用UserProfile创建信号时违反了唯一约束,python,django,django-rest-framework,Python,Django,Django Rest Framework,因此,我创建了一个信号,每当我在我的管理员中创建一个新用户时,它都会自动创建一个UserProfile 代码如下所示: @receiver(post_save, sender=settings.AUTH_USER_MODEL) def create_user_profile(sender, instance, created, **kwargs): if created: UserProfile.objects.get_or_create(user=instance)

因此,我创建了一个信号,每当我在我的管理员中创建一个新用户时,它都会自动创建一个UserProfile

代码如下所示:

@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        UserProfile.objects.get_or_create(user=instance)
一切正常,直到我尝试在Django Rest框架API中创建UserProfile扩展模型

然后,我得到一个
重复的键值,该键值违反了唯一约束

<h1>IntegrityError at /api/v1/space/</h1>
<pre class="exception_value">duplicate key value violates unique constraint &quot;users_userprofile_user_id_key&quot;
DETAIL:  Key (user_id)=(61) already exists.
</pre>

我认为您的问题可能归结为使用get_或_create,您应该只使用create即

UserProfile.objects.create(user=instance)

通过API创建用户配置文件时是否要创建用户?如果是这样,您的模型视图集中的create方法如何?如果您使用的是默认设置,我猜您是在post请求中发送用户。因此,创建用户配置文件时,此处的流程应为:

  • 使用用户id发送POST请求。此用户已创建
  • 用户配置文件是在视图中创建的
  • 由于用户是在之前创建的,因此它不应触发此“post_save”信号
  • 我猜可能会发生什么:

  • 发送请求时未创建用户实例
  • 序列化程序验证通过,因为一切正常
  • 在创建UserProfile时,由于用户关系不能为null,它会创建一个用户实例,触发信号并创建UserProfile
  • 创建用户实例后,它尝试保存新的UserProfile实例,但无法保存,因为它已经存在于数据库中(由用户模型中的post_save信号创建)
  • 我在此附上create方法的源代码以及相应的注释:

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.DATA, files=request.FILES)
    
        if serializer.is_valid(): # It passes because here there are no new objects created yet
            self.pre_save(serializer.object)
            self.object = serializer.save(force_insert=True) # It creates the User (triggering the signal) instance and then when saving UserProfile, it give the integrity error
            self.post_save(self.object, created=True)
            headers = self.get_success_headers(serializer.data)
            return Response(serializer.data, status=status.HTTP_201_CREATED,
                            headers=headers)
    
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    
    我的建议是:

  • 更改创建新用户配置文件时要执行的信号,以便它添加新用户。这是做这件事的正常方式(至少是我以前做的)。这将在admin和api中工作
  • 如果不可能使用1,则不提供UserProfile端点,而是对用户执行该操作。这样,它的工作方式与您的管理员完全相同
  • 如果1和2不可能,请重写create方法并仅创建用户实例。这样做的问题是,当在管理员中创建配置文件时,配置文件将是空的

  • 我只尝试了
    create
    ,但也遇到了同样的错误。您对如何解决这个问题有什么想法吗?您是否能够将这个唯一约束冲突的完整堆栈跟踪添加到上面的问题中?这可能会提供更多的线索。我已经用堆栈跟踪更新了上面的代码,但我不确定它是否会有帮助。我认为适当的方法是创建您自己的自定义用户。这很容易。在可能的情况下,一般应避免使用1到1。创建自定义用户并不是特别困难,也不是特别困难,可以避免很多混乱。@user2734679我明白了,但这是遗留代码,所以我不能真正改变那么多。。你不知道解决这个问题的方法吗?你能包括你的用户档案的模型吗?您正在重写save方法吗?对于DRF,您使用的是视图集、视图、混合还是什么?@djangozone我已经用您要求的代码进行了更新。我使用的是
    ModelViewSet
    ,我没有覆盖save方法谢谢你的回答。我仍然不确定要使用哪个建议,因为在管理中,我需要添加用户,然后是用户配置文件,但在API中,我需要添加用户配置文件,然后才是用户。相反,我可能最终会优先考虑API,并且在管理员界面中,在需要时总是手动关联,因为它将被较少使用。您可以尝试重写create方法,以便在保存UserProfile之前创建用户实例。这可能行得通。那个覆盖看起来有点不正常,所以我有点害怕。你有没有一个例子来说明我如何首先强制创建外键?好吧,忽略前面的评论。正如我所说的,这个覆盖将起作用,但是您的UserProfile实例将为空,因为它是使用User类的post_save信号创建的,所以通过api传递的数据将被忽略。我建议优先考虑API。顺便说一句,在admin中,您仍然可以通过UserProfile表单添加用户。
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.DATA, files=request.FILES)
    
        if serializer.is_valid(): # It passes because here there are no new objects created yet
            self.pre_save(serializer.object)
            self.object = serializer.save(force_insert=True) # It creates the User (triggering the signal) instance and then when saving UserProfile, it give the integrity error
            self.post_save(self.object, created=True)
            headers = self.get_success_headers(serializer.data)
            return Response(serializer.data, status=status.HTTP_201_CREATED,
                            headers=headers)
    
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)