DRF - Upload a valid image - django

Hope someone would be able to help me out here.
I am trying to update an image on a table called MyCards, when updating this image the system should then look to see if this image contains certain word, if so then the field points would be increased by one.
But, when trying to update the image I get the following error
{
"image": [
"Upload a valid image. The file you uploaded was either not an image or a corrupted image."
]
}
Not sure how to solve this issue, if anyone could help on it, would be great.
please find here my model, viewset and serializer
MODEL:
class MyCards(models.Model):
profile = models.ForeignKey(AppUserProfile, on_delete=models.CASCADE)
card = models.ForeignKey(Cards, on_delete=models.CASCADE)
points = models.IntegerField(default=0)
image = models.ImageField(upload_to=f'media/app_user/', blank=True)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return self.card.business.business_name
VIEWSET
class MyCardsViewSet(ModelViewSet):
serializer_class = UpdateMyCardsSerializer
queryset = MyCards.objects.all()
def update(self, request, pk=None, *args, **kwargs):
super().update(request, *args, **kwargs)
x = self.get_object()
img = f"media/{x.image}"
result = pytesseract.image_to_string(img)
if "Petel Chang" in result:
x.points += 1
return self.update(request, *args, **kwargs)
SERIALIZER
class UpdateMyCardsSerializer(serializers.ModelSerializer):
class Meta:
model = MyCards
fields = ('profile', 'card', 'points', 'created', 'updated', 'image')

Related

Cant upload multilple images using django admin

I have two models: one is the post model that can have multiple linked images. The image model has a foreign key to the post. That is, the images have a foreign key for a single post. When adding a new post I want to upload multiple images at the same time. Here is the code:
model.py
class Post(models.Model):
title = models.CharField(max_length=255)
thumbnail = models.ImageField(upload_to='thumbnails')
summary = RichTextField()
body = RichTextUploadingField()
created_at = models.DateField(auto_now_add=True)
class Meta:
ordering = ['-created_at',]
def __str__(self):
return self.title
class Imagens(models.Model):
img = models.ImageField(
upload_to = "media/",
)
post = models.ForeignKey(
"Post", on_delete=models.CASCADE, default=1)
admin.py
class ImageAdminForm(forms.ModelForm):
class Meta:
model = Imagens
fields = ['img',]
def __init__(self, *args, **kwargs):
super(ImageAdminForm, self).__init__(*args, **kwargs)
self.fields['img'] = forms.ImageField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
class ImageInline(admin.TabularInline):
model = Imagens
extra = 1
form = ImageAdminForm
class PostAdmin(admin.ModelAdmin):
search_fields = ['title']
inlines = [ImageInline,]
def save_model(self, request, obj, form, change):
obj.save()
files = request.FILES.getlist('img') #he gets nothing
print(files)
for f in files:
x = Imagens.objects.create(post=obj,img=f)
x.save()
admin.site.register(Post, PostAdmin)
The problem is that if I save the post object it saves only one image and if I try to get the list of images it gives an empty list. Sorry I'm new to Django and even python. Every help is welcome.
Well, that's just a workaround. What I did was make the main model share the form with the inlined model. So, on the change page the files appear and I'm not obliged to post the images either, but it's full of fields.
class ImageAdminForm(forms.ModelForm):
imgens = forms.ImageField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
def __init__(self, *args, **kwargs):
super(ImageAdminForm, self).__init__(*args, **kwargs)
self.fields['imgens'].required = False
self.fields['img'] = forms.ImageField()
self.fields['img'].required = False
class ImageInline(admin.TabularInline):
model = Imagens
extra = 1
form = ImageAdminForm
class PostAdmin(admin.ModelAdmin):
search_fields = ['title']
inlines = [ImageInline]
form = ImageAdminForm
def save_model(self, request, obj, form, change):
obj.save()
files = request.FILES.getlist('imgens')
for f in files:
x = Imagens.objects.create(post=obj,img=f)
x.save()
admin.site.register(Post, PostAdmin)

REST Django - How to Modify a Serialized File Before it is Put Into Model

I am hoping that I can find a way to resize an uploaded image file before it is put into the database.
I am new to Django with REST, so I am not sure how this would be done. It seems that whatever is serialized is just kind of automatically railroaded right into the model. Which I suppose is the point (it's certainly an easy thing to setup).
To clarify, I already have a function tested and working that resizes the image for me. That can be modified as needed and is no problem for me. The issue really is about sort of "intercepting" the image, making my changes, and then putting it into the model. Could someone help me out with some ideas of tactics to get that done? Thanks.
The Model:
class Media(models.Model):
objects = None
username = models.ForeignKey(User, to_field='username',
related_name="Upload_username",
on_delete=models.DO_NOTHING)
date = models.DateTimeField(auto_now_add=True)
media = models.FileField(upload_to='albumMedia', null=True)
file_type = models.CharField(max_length=12)
MEDIA_TYPES = (
('I', "Image"),
('V', "Video")
)
media_type = models.CharField(max_length=1, choices=MEDIA_TYPES, default='I')
user_access = models.CharField(max_length=1, choices=ACCESSIBILITY, default='P')
class Meta:
verbose_name = "MediaManager"
The View with post method:
class MediaView(APIView):
queryset = Media.objects.all()
parser_classes = (MultiPartParser, FormParser)
permission_classes = [permissions.IsAuthenticated, ]
serializer_class = MediaSerializer
def post(self, request, *args, **kwargs):
user = self.request.user
print(user.username)
request.data.update({"username": user.username})
media_serializer = MediaSerializer(data=request.data)
# media_serializer.update('username', user.username)
if media_serializer .is_valid():
media_serializer.save()
return Response(media_serializer.data, status=status.HTTP_201_CREATED)
else:
print('error', media_serializer.errors)
return Response(media_serializer.errors,status=status.HTTP_400_BAD_REQUEST)
The Serializer:
class MediaSerializer(serializers.ModelSerializer):
class Meta:
model = Media
fields = '__all__'
def to_representation(self, instance):
data = super(MediaSerializer, self).to_representation(instance)
return data
You can use validate method to validate and/or change the values from data dictionary.
class MediaSerializer(serializers.ModelSerializer):
...
def validate(self, data):
value_from_form = data['value_from_form']
value_from_form = 'Something else'
data['value_from_form'] = value_from_form
return data

Custom Django FileField url widget won't upload any file in admin change_form

I have a Files table with information about uploaded files in a remote directory. This is the model for that table:
class Files(models.Model):
id = models.AutoField(primary_key=True)
subjectid = models.ForeignKey('Subjects', models.DO_NOTHING, db_column='subjectid')
filetypeid = models.ForeignKey(FileTypes, models.DO_NOTHING, db_column='filetypeid')
filedescid = models.ForeignKey(FileDescription, models.DO_NOTHING, db_column='filedescid')
filepath = models.CharField(max_length=45, blank=True, null=True)
filename = models.FileField(upload_to='attachments/', blank=True, null=True)
ispublic = models.IntegerField(choices=YESNO)
extra_info = models.CharField(max_length=255, blank=True, null=True)
def __str__(self):
return self.filename.name or ''
class Meta:
managed = False
db_table = 'files'
verbose_name_plural = 'files'
I've created my own URL widget to replace the Django FileField url shown as 'Currently:' in the change_form template. The link points to a view that downloads the file. So far, so good it works but the problem is that when I try to add a new file I can select the new file with the Browse file button but when I click on Save the field filename field is empty and no file is uploaded.
class MyAdminURLFieldWidget(URLInput):
template_name = 'admin/widgets/url.html'
def __init__(self, attrs=None):
#final_attrs = {'class': 'vURLField'}
final_attrs = {'type': 'file'}
if attrs is not None:
final_attrs.update(attrs)
super(MyAdminURLFieldWidget, self).__init__(attrs=final_attrs)
def get_context(self, name, value, attrs):
context = super(MyAdminURLFieldWidget, self).get_context(name, value, attrs)
context['current_label'] = _('Currently:')
context['change_label'] = _('Change:')
context['widget']['href'] = smart_urlquote('/DownloadView/' + str(value.instance.id) + '/attachment/') if value else ''
return context
class FilesAdmin(admin.ModelAdmin):
list_display = ('id', '_animalid', '_filename', '_filedesc', 'ispublic', 'extra_info')
search_fields = ('subjectid__animalid','filename')
list_per_page = 50
def formfield_for_dbfield(self, db_field, **kwargs):
if db_field.name == 'filename':
request = kwargs.pop("request", None)
kwargs['widget'] = MyAdminURLFieldWidget
return db_field.formfield(**kwargs)
else:
return super(FilesAdmin, self).formfield_for_dbfield(db_field, **kwargs)
def _animalid(self, obj):
return obj.subjectid.animalid
def _filename(self, obj):
return obj.filename.name
def _filedesc(self, obj):
return obj.filedescid.description
Can anybody tell what I'm missing here?
Hi lost Django community,
I will answer my own question since it seems that nobody was able to realize the answer. It happens that as newbie I'm following examples I've found here and there but there is little about sub-classing the FileField associated widget. So, after diving deep into the Django code I've found the answer. In my case the problem was I derived my MyAdminURLFieldWidget from URLInput instead of the correct subclass ClearableFileInput.
You are welcome.

Django Rest Framework: Uploading a Image

I can't save the image to the image field.
Error
"image": [
"No file was submitted."
]
models.py
class MyImages(models.Model):
name = models.CharField(max_length=255)
image = models.ImageField(upload_to='myphoto', null=False, max_length=255, blank=False)
views.py
class ImageList(APIView):
parser_classes = (MultiPartParser, FileUploadParser,)
def post(self, request):
file_serializer = MyImageSerializer(data=request.data)
if file_serializer.is_valid():
file_serializer.save()
return Response(file_serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(file_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
serialiser.py
class MyImageSerializer(serializers.ModelSerializer):
class Meta:
model = MyImages
fields = ('id', 'name', 'image')
when using postman for file upload the file name is returned in view.py instead of the file object.
I have also seen these threads but not working
1 2
FileUploadParser populates request.data with a file key containing uploaded file.
However, ImageSerializer needs to serialize image this from the request.
Ergo, you need to specify fields explicitly. e.g.
class ImageFileField(serializers.Field):
def to_representation(self, obj):
return obj.image.url
def to_internal_value(self, data):
return data['file']
class MyImageSerializer(serializers.ModelSerializer):
name = serializers.CharField()
image = ImageFileField(source='*')
class Meta:
model = MyImages
I couldn't find any bug in your code when I tried to reproduce the error.
Make sure that uncheck the application/json content type
Then the postman console will be as follows,

Save and update json data to django models

I have a simple model Class
class Talk(models.Model):
url = models.URLField()
user = models.ForeignKey(User)
category = models.ForeignKey(Category)
description = models.TextField(blank=True, max_length=500)
title = models.TextField(blank=True)
and I connect to oembed api to get data from the url submitted
def get_oembed_info(self):
params = {'url': self.url, 'format': 'json'}
fetch_url = 'http://api.embed.ly/1/oembed?%s' % urllib.urlencode(params)
result = urllib.urlopen(fetch_url).read()
result = json.loads(result)
KEYS = ['title', 'type', 'url', 'description', 'provider_url', 'provider_name', 'width', 'height', 'html', 'thumbnail_url', 'author_url']
for key in KEYS:
if result.has_key(key):
setattr(self, key, result[key])
def save(self):
self.get_oembed_info()
super(Talk, self).save()
It's ok to add a new Talk from Admin but when i try to update the same talk later nothing changes.
Also is this way a good to get the data and store it in DB.
Thanks
Each time you save, you fetch data from the server and overwrite your model fields. You could check whether it's a new object before fetching:
def save(self, *args, **kwargs):
if not self.pk:
self.get_oembed_info()
super(Talk, self).save(*args, **kwargs)