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