如何使 PATCH 方法适用于 Django 应用程序中的部分更新?没有 ImageField 更新,它不起作用
How to make PATCH method work for partial update in Django app? Without ImageField update, it doesn't work
我正在尝试在 Django 网络应用程序中启用部分更新(使用 Django Rest Framework)。
我要更新的模型包括 ImageField。
PATCH 方法在我更新 ImageField 时有效,但在我不更新 ImageField 时无效。
错误消息说
AttributeError:'NoneType' object has no attribute 'items'
我该如何解决?
型号:
class Work(models.Model):
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True, blank=True)
title = models.CharField(max_length=120)
made_date = models.DateField(default=datetime.date.today, null=True, blank=True)
note = models.TextField(max_length=2000, null=True, blank=True)
image = models.ImageField(upload_to='work_pic', default='default_image.png')
def __str__(self):
return self.title
def save(self, *args, **kwargs):
if self.image and self.image.name.lower().endswith(('.jpg', '.jpeg')):
pilImage = Img.open(BytesIO(self.image.read()))
for orientation in ExifTags.TAGS.keys():
if ExifTags.TAGS[orientation] == 'Orientation':
break
exif = dict(pilImage._getexif().items())
if exif[orientation] == 3:
pilImage = pilImage.rotate(180, expand=True)
elif exif[orientation] == 6:
pilImage = pilImage.rotate(270, expand=True)
elif exif[orientation] == 8:
pilImage = pilImage.rotate(90, expand=True)
output = BytesIO()
pilImage.save(output, format='JPEG', quality=75)
output.seek(0)
self.image = File(output, self.image.name)
return super(Work, self).save(*args, **kwargs)
序列化器:
class WorkSerializer(serializers.ModelSerializer):
owner = serializers.HiddenField(default=serializers.CurrentUserDefault())
class Meta:
model = Work
fields = '__all__'
def create(self, validated_data):
return Work.objects.create(**validated_data)
视图集:
class WorkViewSet(viewsets.ModelViewSet):
queryset = Work.objects.all()
serializer_class = WorkSerializer
def partial_update(self, request, *args, **kwargs):
kwargs['partial'] = True
return self.update(request, *args, **kwargs)
发送请求的方法(Vue.js):
updateWork: function() {
let formData = new FormData();
//Initial value of currentWork.image is text (path to the original image in the media folder).
//When user upload new image, the file is set to currentWork.image. So condition is match to the if statement bellow.
if (this.currentWork.image instanceof File) {
formData.append("image", this.currentWork.image);
}
formData.append("title", this.currentWork.title);
formData.append("made_date", this.currentWork.made_date);
formData.append("note", this.currentWork.note);
this.loading = true;
axios.patch(`/api/work/${this.currentWork.id}/`, formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
.then((response) => {
this.loading = false;
})
.catch((err) => {
this.loading = false;
console.log(err);
})
错误信息:
Internal Server Error: /api/work/61/
Traceback (most recent call last):
File "/Users/rami/Dev/MySweetsBase/myvenv/lib/python3.6/site-packages/django/core/handlers/exception.py", line 35, in inner
response = get_response(request)
File "/Users/rami/Dev/MySweetsBase/myvenv/lib/python3.6/site-packages/django/core/handlers/base.py", line 128, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/Users/rami/Dev/MySweetsBase/myvenv/lib/python3.6/site-packages/django/core/handlers/base.py", line 126, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/rami/Dev/MySweetsBase/myvenv/lib/python3.6/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "/Users/rami/Dev/MySweetsBase/myvenv/lib/python3.6/site-packages/rest_framework/viewsets.py", line 103, in view
return self.dispatch(request, *args, **kwargs)
File "/Users/rami/Dev/MySweetsBase/myvenv/lib/python3.6/site-packages/rest_framework/views.py", line 483, in dispatch
response = self.handle_exception(exc)
File "/Users/rami/Dev/MySweetsBase/myvenv/lib/python3.6/site-packages/rest_framework/views.py", line 443, in handle_exception
self.raise_uncaught_exception(exc)
File "/Users/rami/Dev/MySweetsBase/myvenv/lib/python3.6/site-packages/rest_framework/views.py", line 480, in dispatch
response = handler(request, *args, **kwargs)
File "/Users/rami/Dev/MySweetsBase/works/viewsets.py", line 13, in partial_update
return self.update(request, *args, **kwargs)
File "/Users/rami/Dev/MySweetsBase/myvenv/lib/python3.6/site-packages/rest_framework/mixins.py", line 70, in update
self.perform_update(serializer)
File "/Users/rami/Dev/MySweetsBase/myvenv/lib/python3.6/site-packages/rest_framework/mixins.py", line 80, in perform_update
serializer.save()
File "/Users/rami/Dev/MySweetsBase/myvenv/lib/python3.6/site-packages/rest_framework/serializers.py", line 209, in save
self.instance = self.update(self.instance, validated_data)
File "/Users/rami/Dev/MySweetsBase/myvenv/lib/python3.6/site-packages/rest_framework/serializers.py", line 981, in update
instance.save()
File "/Users/rami/Dev/MySweetsBase/works/models.py", line 26, in save
exif = dict(pilImage._getexif().items())
AttributeError: 'NoneType' object has no attribute 'items'
class Work(models.Model):
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True, blank=True)
title = models.CharField(max_length=120)
made_date = models.DateField(default=datetime.date.today, null=True, blank=True)
note = models.TextField(max_length=2000, null=True, blank=True)
image = models.ImageField(upload_to='work_pic', default='default_image.png')
def __str__(self):
return self.title
def save(self, *args, **kwargs):
if not self.id:
# add
self.set_image()
else:
# change
this = Work.objects.get(id=self.id)
if this.image != self.image:
self.set_image()
return super(Work, self).save(*args, **kwargs)
def set_image(self):
if self.image and self.image.name.lower().endswith(('.jpg', '.jpeg')):
pilImage = Img.open(BytesIO(self.image.read()))
for orientation in ExifTags.TAGS.keys():
if ExifTags.TAGS[orientation] == 'Orientation':
break
exif = dict(pilImage._getexif().items())
if exif[orientation] == 3:
pilImage = pilImage.rotate(180, expand=True)
elif exif[orientation] == 6:
pilImage = pilImage.rotate(270, expand=True)
elif exif[orientation] == 8:
pilImage = pilImage.rotate(90, expand=True)
output = BytesIO()
pilImage.save(output, format='JPEG', quality=75)
output.seek(0)
self.image = File(output, self.image.name)
试一试
我正在尝试在 Django 网络应用程序中启用部分更新(使用 Django Rest Framework)。
我要更新的模型包括 ImageField。
PATCH 方法在我更新 ImageField 时有效,但在我不更新 ImageField 时无效。
错误消息说
AttributeError:'NoneType' object has no attribute 'items'
我该如何解决?
型号:
class Work(models.Model):
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True, blank=True)
title = models.CharField(max_length=120)
made_date = models.DateField(default=datetime.date.today, null=True, blank=True)
note = models.TextField(max_length=2000, null=True, blank=True)
image = models.ImageField(upload_to='work_pic', default='default_image.png')
def __str__(self):
return self.title
def save(self, *args, **kwargs):
if self.image and self.image.name.lower().endswith(('.jpg', '.jpeg')):
pilImage = Img.open(BytesIO(self.image.read()))
for orientation in ExifTags.TAGS.keys():
if ExifTags.TAGS[orientation] == 'Orientation':
break
exif = dict(pilImage._getexif().items())
if exif[orientation] == 3:
pilImage = pilImage.rotate(180, expand=True)
elif exif[orientation] == 6:
pilImage = pilImage.rotate(270, expand=True)
elif exif[orientation] == 8:
pilImage = pilImage.rotate(90, expand=True)
output = BytesIO()
pilImage.save(output, format='JPEG', quality=75)
output.seek(0)
self.image = File(output, self.image.name)
return super(Work, self).save(*args, **kwargs)
序列化器:
class WorkSerializer(serializers.ModelSerializer):
owner = serializers.HiddenField(default=serializers.CurrentUserDefault())
class Meta:
model = Work
fields = '__all__'
def create(self, validated_data):
return Work.objects.create(**validated_data)
视图集:
class WorkViewSet(viewsets.ModelViewSet):
queryset = Work.objects.all()
serializer_class = WorkSerializer
def partial_update(self, request, *args, **kwargs):
kwargs['partial'] = True
return self.update(request, *args, **kwargs)
发送请求的方法(Vue.js):
updateWork: function() {
let formData = new FormData();
//Initial value of currentWork.image is text (path to the original image in the media folder).
//When user upload new image, the file is set to currentWork.image. So condition is match to the if statement bellow.
if (this.currentWork.image instanceof File) {
formData.append("image", this.currentWork.image);
}
formData.append("title", this.currentWork.title);
formData.append("made_date", this.currentWork.made_date);
formData.append("note", this.currentWork.note);
this.loading = true;
axios.patch(`/api/work/${this.currentWork.id}/`, formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
.then((response) => {
this.loading = false;
})
.catch((err) => {
this.loading = false;
console.log(err);
})
错误信息:
Internal Server Error: /api/work/61/
Traceback (most recent call last):
File "/Users/rami/Dev/MySweetsBase/myvenv/lib/python3.6/site-packages/django/core/handlers/exception.py", line 35, in inner
response = get_response(request)
File "/Users/rami/Dev/MySweetsBase/myvenv/lib/python3.6/site-packages/django/core/handlers/base.py", line 128, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/Users/rami/Dev/MySweetsBase/myvenv/lib/python3.6/site-packages/django/core/handlers/base.py", line 126, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/rami/Dev/MySweetsBase/myvenv/lib/python3.6/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "/Users/rami/Dev/MySweetsBase/myvenv/lib/python3.6/site-packages/rest_framework/viewsets.py", line 103, in view
return self.dispatch(request, *args, **kwargs)
File "/Users/rami/Dev/MySweetsBase/myvenv/lib/python3.6/site-packages/rest_framework/views.py", line 483, in dispatch
response = self.handle_exception(exc)
File "/Users/rami/Dev/MySweetsBase/myvenv/lib/python3.6/site-packages/rest_framework/views.py", line 443, in handle_exception
self.raise_uncaught_exception(exc)
File "/Users/rami/Dev/MySweetsBase/myvenv/lib/python3.6/site-packages/rest_framework/views.py", line 480, in dispatch
response = handler(request, *args, **kwargs)
File "/Users/rami/Dev/MySweetsBase/works/viewsets.py", line 13, in partial_update
return self.update(request, *args, **kwargs)
File "/Users/rami/Dev/MySweetsBase/myvenv/lib/python3.6/site-packages/rest_framework/mixins.py", line 70, in update
self.perform_update(serializer)
File "/Users/rami/Dev/MySweetsBase/myvenv/lib/python3.6/site-packages/rest_framework/mixins.py", line 80, in perform_update
serializer.save()
File "/Users/rami/Dev/MySweetsBase/myvenv/lib/python3.6/site-packages/rest_framework/serializers.py", line 209, in save
self.instance = self.update(self.instance, validated_data)
File "/Users/rami/Dev/MySweetsBase/myvenv/lib/python3.6/site-packages/rest_framework/serializers.py", line 981, in update
instance.save()
File "/Users/rami/Dev/MySweetsBase/works/models.py", line 26, in save
exif = dict(pilImage._getexif().items())
AttributeError: 'NoneType' object has no attribute 'items'
class Work(models.Model):
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True, blank=True)
title = models.CharField(max_length=120)
made_date = models.DateField(default=datetime.date.today, null=True, blank=True)
note = models.TextField(max_length=2000, null=True, blank=True)
image = models.ImageField(upload_to='work_pic', default='default_image.png')
def __str__(self):
return self.title
def save(self, *args, **kwargs):
if not self.id:
# add
self.set_image()
else:
# change
this = Work.objects.get(id=self.id)
if this.image != self.image:
self.set_image()
return super(Work, self).save(*args, **kwargs)
def set_image(self):
if self.image and self.image.name.lower().endswith(('.jpg', '.jpeg')):
pilImage = Img.open(BytesIO(self.image.read()))
for orientation in ExifTags.TAGS.keys():
if ExifTags.TAGS[orientation] == 'Orientation':
break
exif = dict(pilImage._getexif().items())
if exif[orientation] == 3:
pilImage = pilImage.rotate(180, expand=True)
elif exif[orientation] == 6:
pilImage = pilImage.rotate(270, expand=True)
elif exif[orientation] == 8:
pilImage = pilImage.rotate(90, expand=True)
output = BytesIO()
pilImage.save(output, format='JPEG', quality=75)
output.seek(0)
self.image = File(output, self.image.name)
试一试