Django rest framework saving thumbnail image - python

I've recently started developing with django + python and everything was going very smooth until I got stuck into a problem that probably is very simple but I can not solve with my inexperience with the framework/language.
I'm receiving an JSON object through an HTTP Request which contains some data and 2 pictures. Prior to those 2 pictures I wanted to save a thumbnail from one of them but I don't see to get that task done. I can save all the data easily including the 2 images. But I can not see to find a way to generate a way an have that in the DB also, as well the folder structure that I want.
My folders should look like:
pictures
user
originals
processed
thumbnails
otherUser
originals
processed
thumbnails
My goal is: Receive 2 pictures, create a thumbnail from one of them and them save all 3 pictures in 3 separate folders and the path to the Database.
Here's how my model code looks like.
class SomeData(models.Model):
owner = models.ForeignKey('auth.User', related_name='canopeo_data')
adjustments = models.CharField(max_length=10)
latitude = GeopositionField()
longitude = GeopositionField()
notes = models.TextField(null=True, blank=True)
original_image = models.ImageField(upload_to=original_image, max_length=255, blank=True)
processed_image = models.ImageField(null=False, upload_to=processed_image, max_length=255)
thumbnail_image = models.ImageField(null=False, upload_to=thumbnail_image, max_length=255)
date_time = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('date_time',)
def save(self, *args, **kwargs):
super(SomeData, self).save(*args, **kwargs)
def original_image(self, filename):
url = "pictures/%s/originals/%s" % (self.owner.username, filename)
return url
def processed_image(self, filename):
url = "pictures/%s/processed/%s" % (self.owner.username, filename)
return url
def thumbnail_image(self, filename):
url = "pictures/%s/thumbnail/%s" % (self.owner.username, filename)
return url
Serializer code...
class SomeDataSerializer(serializers.HyperlinkedModelSerializer):
#url = serializers.HyperlinkedRelatedField(view_name='data', format='html')
owner = serializers.Field(source='owner.username')
thumbnail_image = serializers.Field(source='original_image')
class Meta:
model = SomeData
fields = ('url', 'adjustments', 'latitude', 'longitude', 'notes', 'original_image', 'processed_image',)
View code...
class SomeDataViewSet(viewsets.ModelViewSet):
queryset = SomeData.objects.all()
serializer_class = SomeDataSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
def pre_save(self, obj):
obj.owner = self.request.user
I've tried many things such as easy_thumbnails, sorl_thumbnail, and some pre made methods on how to do it.. but I can't see to find a solution specific for what I've been wanting.
Thank you very much!

Looks like you have mistake in definition of the SomeDataSerializer. In model SomeData field original_image defined as ImageField, but in serialiser it's just Field, not ImageField. You should use correct field type:
class SomeDataSerializer(serializers.HyperlinkedModelSerializer):
#url = serializers.HyperlinkedRelatedField(view_name='data', format='html')
owner = serializers.Field(source='owner.username')
thumbnail_image = serializers.ImageField(source='original_image')
...

Related

django rest framework upload image to related model using generic.createAPIView

I am scheduling a medical camp at some destination. After reaching the destination i want to upload picture of that destination of mapped destination.
I Created two model for that
One is SiteMap
class SiteMap(models.Model):
MpId = models.IntegerField(verbose_name='MPID')
VisitingDate = models.DateField(default=timezone.now,verbose_name='Date')
Vehical = models.ForeignKey(VehicalMaster,on_delete=models.CASCADE,verbose_name='Vehical')
Doctor = models.ForeignKey(User,on_delete=models.CASCADE,verbose_name='Doctor')
District = models.ForeignKey(District,on_delete=models.CASCADE,verbose_name='District')
Block = models.ForeignKey(Block,on_delete=models.CASCADE,verbose_name='Block')
Panchayat = models.CharField(max_length=120,verbose_name="Panchayat")
Village = models.CharField(max_length=120,verbose_name='Village')
updated = models.DateTimeField(auto_now=True)
And secod one is SiteMapImage
class SiteMapImage(models.Model):
MPID = models.ForeignKey(SiteMap,on_delete=models.CASCADE,verbose_name='MPID')
SiteImage = models.ImageField(default='default.png',upload_to='sitemap/%Y/%m/%d')
Location = models.CharField(max_length=200,verbose_name='Location',null=True,blank=True)
Latitude = models.CharField(max_length=120,verbose_name='Latitude',null=True,blank=True)
Longitue = models.CharField(max_length=120,verbose_name='Longitude',null=True,blank=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return f"{self.MPID}"
def save(self):
super().save()
siteimg = Image.open(self.SiteImage.path)
if siteimg.height>300 or siteimg.width>300:
output_size = (300,300)
siteimg.thumbnail(output_size)
siteimg.save(self.SiteImage.path)
I have created a serializer class for this. Here is the code.
class SiteMapImageSerializer(serializers.ModelSerializer):
class Meta:
model = SiteMapImage
fields = ['MPID','Location','Latitude','Longitue','SiteImage']
and this is my view.py
class SiteMapImageCreateView(generics.CreateAPIView):
lookup_field = 'SiteMap.pk'
serializer_class = SiteMapImageSerializer
def get_queryset(self):
return SiteMapImage.objects.all()
I don't know what wrong i did. but not working in broweser too.
I upload the error image tooo.

How to display an image inside Django Admin's detail view of a model?

I want to display an image inside a detail view of a model, when browsing through Django Admin. I have seen other posts about displaying images in the list view of all instances of a model in Django Admin. But I'm interested in seeing the image on the page where you can edit the data.
models.py
class Label(models.Model):
label = models.TextField()
fragment = models.ForeignKey('Fragment', models.DO_NOTHING, null=True)
in_english = models.BooleanField(default=True)
validated = models.BooleanField(default=False)
def __str__(self):
return str(self.fragment)
admin.py
#admin.register(Label)
class LabelsAdmin(admin.ModelAdmin):
fields = ("label", "in_english", "validated", )
# What I tried. This is not working even after adding 'image' to the fields. I get an error.
# def image(self, obj):
# return format_html('<img src="{0}" />'.format(f"/static/fragments/{obj}.png"))
you create a method like display_image.
def display_image(self, obj):
# get image url
image_url = '<your_image_url>'
if image_url is not None:
return format_html('<img src="{}">', image_url)
return None
Add 'display_image' in fields list
fields = ("label", "in_english", "validated", 'display_image')
then make this field as a readonly
readonly_fields = ['display_image']

Replicating Folder Structure inside the existing folder when updating the model Django

I have a model with image compression enabled
class Course(models.Model):
def upload_location(instance,filename):
return "course_images/%s/%s"%(instance.course_name,filename)
subject = models.ForeignKey(Subject,on_delete=models.CASCADE,null=True,default=None)
course_name = models.CharField(max_length=300,default=None)
author = models.ForeignKey(TeacherProfile,on_delete=models.CASCADE,null=True,default=None)
course_description = models.TextField(null=True)
course_cover = models.ImageField(null=True,blank=True,upload_to=upload_location,default="course_images/default.png")
created_at = models.DateTimeField(default=now)
price = models.IntegerField(default=0,null=True,blank=True)
duration = models.CharField(max_length=20, null=True, blank=True)
is_enrolled = models.BooleanField(default=False)
def save(self, *args, **kwargs):
new_image = compress(self.course_cover)
self.course_cover = new_image
super().save(*args, **kwargs)
def __str__(self):
return self.course_name
When I update this model without sending an image from the frontend folder structure gets replicated inside the existing folder. ex:- Course_images/Science/science.jpg is the initial folder structure when creating an object with this model. But after updating the model without the image I can see another Course_images/Science/science.jpg inside Course_images. This starts to happen after adding the compression method. Without overriding the save method this works fine. Also if I change the image folder replication is not happening.
View of the updatecourse
class UpdateCourse(RetrieveUpdateAPIView):
queryset = Course.objects.all()
serializer_class = CourseCreateSerializer
permission_classes = [IsAuthenticated]
Can anyone state a reason for this scenario. Thank you!
def save(self, *args, **kwargs):
if self.course_cover:
im = Image.open(self.course_cover)
im = im.convert('RGB')
# create a BytesIO object
im_io = BytesIO()
# save image to BytesIO object
im.save(im_io, 'JPEG', quality=10)
temp_name = os.path.split(self.course_cover.name)[1]
self.course_cover.save(temp_name, content=ContentFile(im_io.getvalue()), save=False)
super().save(*args, **kwargs)
I updated save method as above. Problem Solved!

Django model foreignkey queries

So i have this two models in django:
class Course(models.Model):
def get_image_path(self, filename):
return os.path.join('courses', str(self.slug), filename)
def __str__(self):
return self.name
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Course, self).save(*args, **kwargs)
name = models.CharField(max_length=255, verbose_name="Nombre")
description = models.CharField(max_length=255, verbose_name="DescripciĆ³n")
price = models.DecimalField(max_digits=12,decimal_places=2, verbose_name="Precio")
slug = models.SlugField(blank=True, max_length=255)
icon_img = models.ImageField(upload_to=get_image_path, blank=True, null=True, verbose_name="Imagen")
background_color = ColorField(default="#026085")
class Meta:
verbose_name = "curso"
verbose_name_plural = "cursos"
class UserCourse(models.Model):
user = models.ForeignKey(User)
course = models.ForeignKey(Course)
So whenever a user "buys" a course, it is stored in UserCourse. I have a view where the system shows a list of all the courses the user has bought. This is the view code:
def user_course_list_view(request, username):
context_dict = {}
try:
user_courses = UserCourse.objects.filter(user=request.user).course_set
context_dict['courses'] = user_courses
context_dict['heading'] = "Mis cursos"
except:
context_dict['courses'] = None
context_dict['heading'] = "Mis cursos wey"
return render(request, 'courses/course_list.html', context=context_dict)
I dont know where is the error and I cant seem to catch the exception (im using django with docker)
tl;dr
Something like this should work.
usercourse_objects = UserCourse.objects.filter(user=request.user).select_related('course')
user_courses = [x.course for x in usercourse_objects]
Explanation
There are multiple ways to do this, but one way would be to first get all the UserCourse objects for the current user:
usercourse_objects = UserCourse.objects.filter(user=request.user)
Then, for each UserCourse object, get the related Course:
user_courses = [x.course for x in usercourse_objects]
Now, the second line causes N database queries (one for each time we follow the course foreign key relation. To prevent this, the first line can be changed to:
usercourse_objects = UserCourse.objects.filter(user=request.user).select_related('course')
This pre-populates the course attribute of the UserCourse objects. More info about select_related() can be found here.

Getting Request in admin.py

I have a model like this:
class Item(models.Model):
code = models.CharField(max_length=200, unique=True)
barcode = models.CharField(max_length=300)
desc = models.CharField('Description',max_length=500)
display_desc = models.CharField('Description',max_length=500,
blank=True, null=True)
price = models.FloatField()
discountable = models.BooleanField(blank=True, default=False)
image_path = models.CharField(max_length=300,unique=True, blank=True, null=True)
def __unicode__(self):
return self.code + ' : ' + self.desc
But unfortunately, I don't want to store the item's image in the database, instead I want to store the image path in the server in the image_path column.
So, I created a custom admin.py for this object so that I could edit/insert the object thru the Django admin module. As a result, below is the customized admin.py
class ItemAdminForm(forms.ModelForm):
file_upload = forms.FileField(required=False)
class Meta:
model = Item
def __init__(self, *args, **kwargs):
super(ItemAdminForm, self).__init__(*args,**kwargs)
#if kwargs.has_key('instance'):
# instance = kwargs['instance']
# self.initial['file_upload'] = instance.file_upload
def handle_uploaded_file(f):
destination = open('D:/Project/pensel/penselshop/static/picture', 'wb+')
for chunk in f.chunks():
destination.write(chunk)
destination.close()
return f.name
def save(self,commit=True):
name = None
extension = None
#error here! How could I get the request?
miniform = ItemAdminForm(request.POST, request.FILES)
if miniform.is_valid():
name = handle_uploaded_file(request.FILES['file_upload'])
extension = name.split('.')[1]
model = super(ItemAdminForm, self).save(commit=False)
model.image_path = '/static/picture/' + model.code + extension
if commit:
model.save()
return model
However, during processing the save() function, I noticed that there is an error in getting the request. How can I get the request so that I could retrieve the file? I noticed that the request is automatically added in views.py, but not admin.py
Django's ImageField and FileField fields don't actually store the image in the database either. All that is stored in the database is the path, which you can control yourself. The actual image file is stored on the filesystem. So I'm not sure why you are going to all this trouble...?
But to answer your question of how to get the request in the admin, you can override ModelAdmin.save_model().

Categories

Resources