Django 完整性错误1048:“;列不能为空";

Django 完整性错误1048:“;列不能为空";,django,django-rest-framework,django-serializer,Django,Django Rest Framework,Django Serializer,在一个项目中,我让应用程序用户和评论,通过ForeignKey连接 如果我编辑一个没有评论的用户,我可以毫无问题地编辑。我甚至可以添加一条评论 但是当我试图保存/修补已经有评论的用户的任何用户数据时,我得到了IntegrityError 编辑: 实际上,我两次都使用了PUT方法 users\models.py: class User(AbstractBaseUser): created_at = models.DateTimeField(auto_now_add=True

在一个项目中,我让应用程序
用户
评论
,通过
ForeignKey
连接

如果我编辑一个没有评论的用户,我可以毫无问题地编辑。我甚至可以添加一条评论

但是当我试图保存/修补已经有评论的用户的任何用户数据时,我得到了
IntegrityError

编辑: 实际上,我两次都使用了
PUT
方法

users\models.py

    class User(AbstractBaseUser):
        created_at = models.DateTimeField(auto_now_add=True, editable=False))
        ....
        #nothing special here
class Comments(models.Model):
    created_at = models.DateTimeField(auto_now_add=True, null=True, blank=True, editable=False)
    modified_at = models.DateTimeField(auto_now=True, editable=False)
    created_by = models.ForeignKey(User, null=True, editable=False, related_name='%(class)s_created', on_delete=models.SET_NULL)
    modified_by = models.ForeignKey(User, null=True, editable=False, related_name='%(class)s_modified', on_delete=models.SET_NULL)

    type = models.CharField(max_length=50, blank=True, default='')
    content = models.CharField(max_length=100, blank=True, default='')
    owner = models.ForeignKey(User, null=True, blank=True, related_name='comments', on_delete=models.SET_NULL)
class UserViewSet(viewsets.ModelViewSet):
    """
    This viewset automatically provides `list` and `detail` actions.
    """
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = (IsSpecialistAllOrCustomerRead,)

    ...
    ...
  
    def retrieve(self, request, *args, **kwargs):

        retrieve_type = self.request.query_params.get('retrieve_type', None)

        if retrieve_type is None:
            instance = self.get_object()
            serializer = self.get_serializer(instance)
            return Response(serializer.data)

        elif retrieve_type  == 'news_counts' and User.objects.filter(id=request.user.id).filter(groups__id=1):
            instance = self.get_object()
            user_id = instance.id

            response_dict = dict()
            sql = """
                 SELECT COUNT(o.id) as requests from projects_project o
                 LEFT JOIN projects_project_participants op ON (o.id = op.project_id)
                 WHERE op.project_id IS NULL;
                """
            response_dict.update(executeRawSQL(sql)[0])

            sql = """
                 SELECT COUNT(r.id) as reminders
                 FROM reminders_reminder r, reminders_reminder_participants rp
                 WHERE r.id = rp.reminder_id AND rp.user_id = {0} AND r.done = 0 AND r.date_time <= CURDATE();
                """.format(*(user_id,))
            response_dict.update(executeRawSQL(sql)[0])

            return Response(response_dict)
        else:
            return Response(dict())



    def perform_create(self, serializer):
        if self.request.user.is_anonymous:
            serializer.save()
        else:
            serializer.save(created_by=self.request.user)

    def perform_update(self, serializer):
        serializer.save(modified_by=self.request.user)  #    <--- Traced to here 

    def perform_destroy(self, instance):
        for project in instance.projects.all():
            #print dir(project)
            project.customer = None
            project.save()

        instance.delete()
comments\models.py

    class User(AbstractBaseUser):
        created_at = models.DateTimeField(auto_now_add=True, editable=False))
        ....
        #nothing special here
class Comments(models.Model):
    created_at = models.DateTimeField(auto_now_add=True, null=True, blank=True, editable=False)
    modified_at = models.DateTimeField(auto_now=True, editable=False)
    created_by = models.ForeignKey(User, null=True, editable=False, related_name='%(class)s_created', on_delete=models.SET_NULL)
    modified_by = models.ForeignKey(User, null=True, editable=False, related_name='%(class)s_modified', on_delete=models.SET_NULL)

    type = models.CharField(max_length=50, blank=True, default='')
    content = models.CharField(max_length=100, blank=True, default='')
    owner = models.ForeignKey(User, null=True, blank=True, related_name='comments', on_delete=models.SET_NULL)
class UserViewSet(viewsets.ModelViewSet):
    """
    This viewset automatically provides `list` and `detail` actions.
    """
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = (IsSpecialistAllOrCustomerRead,)

    ...
    ...
  
    def retrieve(self, request, *args, **kwargs):

        retrieve_type = self.request.query_params.get('retrieve_type', None)

        if retrieve_type is None:
            instance = self.get_object()
            serializer = self.get_serializer(instance)
            return Response(serializer.data)

        elif retrieve_type  == 'news_counts' and User.objects.filter(id=request.user.id).filter(groups__id=1):
            instance = self.get_object()
            user_id = instance.id

            response_dict = dict()
            sql = """
                 SELECT COUNT(o.id) as requests from projects_project o
                 LEFT JOIN projects_project_participants op ON (o.id = op.project_id)
                 WHERE op.project_id IS NULL;
                """
            response_dict.update(executeRawSQL(sql)[0])

            sql = """
                 SELECT COUNT(r.id) as reminders
                 FROM reminders_reminder r, reminders_reminder_participants rp
                 WHERE r.id = rp.reminder_id AND rp.user_id = {0} AND r.done = 0 AND r.date_time <= CURDATE();
                """.format(*(user_id,))
            response_dict.update(executeRawSQL(sql)[0])

            return Response(response_dict)
        else:
            return Response(dict())



    def perform_create(self, serializer):
        if self.request.user.is_anonymous:
            serializer.save()
        else:
            serializer.save(created_by=self.request.user)

    def perform_update(self, serializer):
        serializer.save(modified_by=self.request.user)  #    <--- Traced to here 

    def perform_destroy(self, instance):
        for project in instance.projects.all():
            #print dir(project)
            project.customer = None
            project.save()

        instance.delete()
错误消息中的跟踪指向
users\serializers.py
中函数
update
中的行
cmnt.save()
,如下所示:

def update(self, instance, validated_data):
    info = model_meta.get_field_info(instance)

    #extract nested user information to handle those separately
    ...
    ...
    comments_data = validated_data.pop('comments', None)
    ...
    ...

    # update user fields
    
    # Simply set each attribute on the instance, and then save it.
    # Note that unlike `.create()` we don't need to treat many-to-many
    # relationships as being a special case. During updates we already
    # have an instance pk for the relationships to be associated with.
    m2m_fields = []
    for attr, value in validated_data.items():
        if attr in info.relations and info.relations[attr].to_many:
            m2m_fields.append((attr, value))
        else:
            setattr(instance, attr, value)

    instance.save()

    # Note that many-to-many fields are set after updating instance.
    # Setting m2m fields triggers signals which could potentially change
    # updated instance and we do not want it to collide with .update()
    for attr, value in m2m_fields:
        field = getattr(instance, attr)
        field.set(value)

    update_session_auth_hash(self.context.get('request'), instance)

    #create, update, delete related entities

    if comments_data and comments_data is not None:
        #remove items
        cmnt_ids = [item.get('id') for item in comments_data]
        for comment in instance.comments.all():
            if comment.id not in cmnt_ids:
                cmnt.delete()

        #create or update items
        for comment in comments_data:
            cmnt = Comment(owner=instance, **comment)
            cmnt.save()    #  <--- Trace points here
    else:
        #delete all items
        for comment in instance.comments.all():
            comment.delete()
users\views.py
中:

    class User(AbstractBaseUser):
        created_at = models.DateTimeField(auto_now_add=True, editable=False))
        ....
        #nothing special here
class Comments(models.Model):
    created_at = models.DateTimeField(auto_now_add=True, null=True, blank=True, editable=False)
    modified_at = models.DateTimeField(auto_now=True, editable=False)
    created_by = models.ForeignKey(User, null=True, editable=False, related_name='%(class)s_created', on_delete=models.SET_NULL)
    modified_by = models.ForeignKey(User, null=True, editable=False, related_name='%(class)s_modified', on_delete=models.SET_NULL)

    type = models.CharField(max_length=50, blank=True, default='')
    content = models.CharField(max_length=100, blank=True, default='')
    owner = models.ForeignKey(User, null=True, blank=True, related_name='comments', on_delete=models.SET_NULL)
class UserViewSet(viewsets.ModelViewSet):
    """
    This viewset automatically provides `list` and `detail` actions.
    """
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = (IsSpecialistAllOrCustomerRead,)

    ...
    ...
  
    def retrieve(self, request, *args, **kwargs):

        retrieve_type = self.request.query_params.get('retrieve_type', None)

        if retrieve_type is None:
            instance = self.get_object()
            serializer = self.get_serializer(instance)
            return Response(serializer.data)

        elif retrieve_type  == 'news_counts' and User.objects.filter(id=request.user.id).filter(groups__id=1):
            instance = self.get_object()
            user_id = instance.id

            response_dict = dict()
            sql = """
                 SELECT COUNT(o.id) as requests from projects_project o
                 LEFT JOIN projects_project_participants op ON (o.id = op.project_id)
                 WHERE op.project_id IS NULL;
                """
            response_dict.update(executeRawSQL(sql)[0])

            sql = """
                 SELECT COUNT(r.id) as reminders
                 FROM reminders_reminder r, reminders_reminder_participants rp
                 WHERE r.id = rp.reminder_id AND rp.user_id = {0} AND r.done = 0 AND r.date_time <= CURDATE();
                """.format(*(user_id,))
            response_dict.update(executeRawSQL(sql)[0])

            return Response(response_dict)
        else:
            return Response(dict())



    def perform_create(self, serializer):
        if self.request.user.is_anonymous:
            serializer.save()
        else:
            serializer.save(created_by=self.request.user)

    def perform_update(self, serializer):
        serializer.save(modified_by=self.request.user)  #    <--- Traced to here 

    def perform_destroy(self, instance):
        for project in instance.projects.all():
            #print dir(project)
            project.customer = None
            project.save()

        instance.delete()
class UserViewSet(ViewSet.ModelViewSet):
"""
此视图集自动提供“列表”和“详细信息”操作。
"""
queryset=User.objects.all()
serializer\u class=UserSerializer
权限\类=(IsSpecialInstallorCustomerRead,)
...
...
def检索(self、request、*args、**kwargs):
retrieve\u type=self.request.query\u params.get('retrieve\u type',None)
如果检索类型为“无”:
instance=self.get\u对象()
serializer=self.get\u序列化程序(实例)
返回响应(serializer.data)
elif retrieve_type=='news_counts'和User.objects.filter(id=request.User.id).filter(groups_id=1):
instance=self.get\u对象()
user\u id=instance.id
答复_dict=dict()
sql=”“”
选择COUNT(o.id)作为来自项目的请求
左侧加入项目\u项目\u参与者op ON(o.id=op.project\u id)
其中op.project_id为空;
"""
响应命令更新(executeRawSQL(sql)[0])
sql=”“”
选择计数(r.id)作为提醒
从提醒\u提醒r、提醒\u提醒\u参与者rp

其中r.id=rp.rementer\u id和rp.user\u id={0},r.done=0和r.date\u time由于所进行的更新调用的类型而产生错误

PUT方法更新所有字段,而PATCH用于更新单个字段。 update()方法接受PUT和PATCH请求,并使用值“partial”对其进行区分

因为您使用的是ModelViewSet,它会在补丁请求时自动设置partial=True,所以您不必担心它。您只需要发送一个补丁API调用,而不是PUT

有关ModelViewSet的详细信息:


对于在ViewSet中使用其他方法时的部分参数:

我将添加完整的跟踪是否发送修补请求或使用POST修补它们?请添加您的ViewSet和APIcall@Neeraj哦,我看到AngularJS前端将其处理为PUT,这意味着POST,对吗?但不一样…PUT方法会更新所有内容,因此它需要每个field…虽然修补程序用于部分更新,但在此特定场景中,您只能发送一个您想要的字段。使用postman使用修补程序尝试一次。此外,如果您可以共享viewset,我可以对其提出更多建议。PS:我的意思是放上以前的注释而不是发布道歉我是否理解这一点?:即使我创建了一个新的
注释de>,Ii应该使用PATCH,因为我基本上是在修补
用户
数据,因为它们是通过
ForeignKey
连接的,并且因为我通过
UserSerializer
输入注释。api调用“但是当我试图保存/修补已经有注释的用户的任何用户数据时“这个场景应该是一个补丁请求,而不是put,这就是我的意思,我必须只使用补丁来尝试,否则我将不得不编写大量代码。非常感谢你!我希望这能解决问题。我很快就会试试的。当然!如果仍然抛出错误,请删除注释。理想情况下不应该是:P