save thumbnail image path django python - django

i am generating thumbnail and i want to save image path to database when i upload from admin and api:
class Image(models.Model):
license_type = (
('Royalty-Free','Royalty-Free'),
('Rights-Managed','Rights-Managed')
)
image_number = models.CharField(default=random_image_number,max_length=12,unique=True)
title = models.CharField(default=random_image_number,max_length = 100)
image = models.ImageField(upload_to = 'image' , default = 'demo/demo.png')
thumbnail = models.ImageField(upload_to='thumbs')
category = models.ForeignKey('Category', null=True, blank=True, on_delete=models.CASCADE)
shoot = models.ForeignKey(ImageShoot, on_delete=models.CASCADE, related_name='Image', null=True,blank=True)
image_keyword = models.TextField(max_length=1000)
credit = models.CharField(max_length=150, null=True)
location = models.CharField(max_length=100, null=True)
license_type = models.CharField(max_length=20,choices=license_type, default='')
uploaded_at = models.TimeField(auto_now_add=True)
def __str__(self):
return self.title
def save(self, *args, **kwargs):
super(Image, self).save(*args, **kwargs)
if not self.make_thumbnail():
raise Exception('Could not create thumbnail - is the file type valid?')
def make_thumbnail(self):
fh = storage.open(self.image.path)
image = PILImage.open(fh)
image.thumbnail((400,400),PILImage.ANTIALIAS)
fh.close()
thumb_name, thumb_extension = os.path.splitext(self.image.path)
thumb_extension = thumb_extension.lower()
thumb_filename = thumb_name + '_thumb' + thumb_extension
temp_thumb = BytesIO()
image.save(temp_thumb, FTYPE)
temp_thumb.seek(0)
self.thumbnail.save(thumb_filename, ContentFile(temp_thumb.read()), save=True)
temp_thumb.close()
return True
this if we upload image from admin
admin.py:
#admin.register(Image)
class ImageAdmin(admin.ModelAdmin):
readonly_fields=['image_number','uploaded_at']
fields = ['title','image_number','shoot','category',
'image','image_keyword','thumbnail','credit','license_type','location','uploaded_at']
this is my views for api currently just uploading bulk image with out thumbnail how can i create thumbnail from this :
views.py:
class EventImageUploadView(APIView):
def post(self, request,category):
#title = forms.CharField(max_length = 100)
file = request.data['file']
data={
'image':file,
'category_id':category
}
EventsImage.objects.create(**data)
return JsonResponse(json.dumps({'message': "Uploaded"}), status=200, safe=False)
i get this error and its generating multiple images i dont know what causing recursion:
maximum recursion depth exceeded in comparison
backtrace:
File "/home/tboss/Desktop/environment/live/backend/venv/lib/python3.7/site-packages/PIL/TiffImagePlugin.py", line 319, in __init__
if isinstance(value, Fraction):
File "/home/tboss/Desktop/environment/live/backend/venv/lib/python3.7/abc.py", line 139, in __instancecheck__
return _abc_instancecheck(cls, instance)
RecursionError: maximum recursion depth exceeded in comparison

Related

How to work with an image before saving it in my model?

I have a model where a field exists:
image=models.ImageField(upload_to='products/')
models.py
class Product(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
name = models.CharField(max_length=200)
code_number = models.IntegerField(verbose_name='Bar Code')
image = models.ImageField(upload_to='products/')
purchase_price = models.DecimalField(max_digits=10, decimal_places=2)
sale_price= models.DecimalField(max_digits=10, decimal_places=2)
tax = models.ManyToManyField(Tax, blank=True, related_name="tax")
pro_quantity =models.DecimalField(max_digits=10, decimal_places=2, default=0)
description = models.TextField()
branch = models.ForeignKey(Branch, on_delete=models.CASCADE, related_name="branchesp", blank=True, null=True)
created_date = models.DateTimeField(
default=timezone.now)
published_date = models.DateTimeField(
blank=True, null=True)
def publish(self):
self.published_date = timezone.now()
self.save()
def __str__(self):
return self.name
views.py
class ProductCreate(View):
form_class = ProductForm
template_name = 'pos/product_form.html'
def get(self, request, *args, **kwargs):
form = self.form_class()
return render(request, self.template_name, {'form': form})
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST, request.FILES)
form.instance.user = self.request.user
if form.is_valid():
# Procesa la imagen subida
image_content = request.FILES['image'].read()
image = resize_image_with_aspect(image_content, 800, 600)
image_file = tempfile.NamedTemporaryFile(mode='wb', suffix='.webp')
image.save(image_file, format="webp", optimize=True, quality=85)
image_file = open(image_file.name, 'rb')
form.instance.image = image_file.read()
image_file = BytesIO(form.instance.image)
image_file.seek(0)
form.instance.image = File(image_file)
product = form.save(commit=False)
product.save()
image_file.close()
return redirect('inventory')
else:
print(form.errors)
return redirect('inventory')
utils.py
import io
from PIL import Image
def resize_image_with_aspect(image_content, width, height):
image = Image.open(io.BytesIO(image_content))
original_width, original_height = image.size
ratio = original_width / original_height
if width > height:
height = int(width / ratio)manteniendo el ratio
else:
width = int(height * ratio)
image = image.resize((width, height), Image.ANTIALIAS)
return image
Now, it seems to work fine but the image doesn't save. What could I be doing wrong?
I want to optimize, resize, and change to webp any type of image that is uploaded through the form and only save the already-converted image in /media/products and the database

Django error: The Items could not be created because the data didn't validate

I get the following error:
ValueError at /create-items/
The Items could not be created because the data didn't validate., and can't find out what the issue is...
Views.py
def createMulitpleItemsPage(request):
currency = '€'
ItemFormSet = modelformset_factory(Items, form=CreateItemFormset, extra=1)
qs = Items.objects.none()
user = request.user.profile
formset = ItemFormSet(request.POST or None, queryset=qs, form_kwargs={'user': user})
# Create multiple items
if request.method == 'GET':
user = request.user.profile
ItemFormSet = modelformset_factory(Items, form=CreateItemFormset, extra=1)
qs = Items.objects.none()
formset = ItemFormSet(request.POST or None, queryset=qs, form_kwargs={'user': user})
context = {'formset': formset}
if request.method == 'POST':
print('printing POST: ', request.POST)
print('printing Errors: ', formset.errors)
if formset.is_valid():
formset = CreateItemFormset(user=request.user.profile, data=request.POST)
parent = formset.save(commit=False)
parent = formset.save()
for form in formset:
newitems = form.save(commit=False)
newitems.user = request.user.profile
newitems.save()
return redirect('items')
return render(request, 'base/mass_create_items.html', context)
Forms.py
class CreateItemFormset(ModelForm):
def __init__(self, user, *args, **kwargs):
super(CreateItemFormset, self).__init__(*args, **kwargs)
qs = Categories.objects.filter(user=user)
self.fields['item_category'] = ModelChoiceField(queryset=qs)
class Meta:
model = Items
fields = ['item_name', 'item_category', 'item_start_date', 'item_end_date', 'item_purchase_price', 'item_rest_value']
Models.py
class Items(models.Model):
user = models.ForeignKey(Profile, on_delete=models.CASCADE, null=True, blank=True)
item_name = models.CharField(max_length=200, null=False, blank=False)
item_category = models.ForeignKey(Categories, null=True, blank=True, on_delete=models.SET_NULL)
item_created_at = models.DateTimeField(auto_now_add=True, null=True, blank=False)
item_updated_at = models.DateTimeField(auto_now=True, null=True, blank=False)
item_start_date = models.DateField(null=True, blank=False)
item_end_date = models.DateField(null=True, blank=False)
item_purchase_price = models.FloatField(null=True, blank=False)
item_rest_value = models.FloatField(default=0, null=True, blank=False)
item_saving_goal = models.FloatField(default=0, null=True, blank=False)
item_date_delta = models.FloatField(default=0, null=True, blank=False)
item_days_passed = models.FloatField(default=0, null=True, blank=False)
item_currently_saved = models.FloatField(default=0, null=True, blank=False)
item_percentage_saved = models.FloatField(default=0.01, null=True, blank=False)
item_monthly_saving = models.FloatField(default=0, null=True, blank=False)
def save(self, *args, **kwargs):
self.item_saving_goal = self.item_purchase_price - self.item_rest_value
self.item_date_delta = (self.item_end_date.year - self.item_start_date.year) * 12 + ( self.item_end_date.month - self.item_start_date.month )
self.item_days_passed = (date.today().year - self.item_start_date.year) * 12 + ( date.today().month - self.item_start_date.month )
self.item_currently_saved = self.item_saving_goal * (self.item_days_passed / self.item_date_delta )
self.item_percentage_saved = self.item_currently_saved / self.item_saving_goal * 100
self.item_monthly_saving = self.item_saving_goal / self.item_date_delta
super().save(*args, **kwargs)
Error looks like this:
Internal Server Error: /create-items/
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/core/handlers/exception.py",
line 47, in inner
response = get_response(request)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/core/handlers/base.py",
line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/contrib/auth/decorators.py",
line 21, in _wrapped_view
return view_func(request, *args, **kwargs)
File "/Users/jelledekker/Library/Mobile Documents/com~apple~CloudDocs/Django/Aurelian web/base/views.py", line
304, in createMulitpleItemsPage
parent = formset.save(commit=False)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/forms/models.py",
line 458, in save
raise ValueError(
ValueError: The Items could not be created because the data didn't validate.
You are testing the formset for validity before binding it to POST!
if formset.is_valid():
formset = CreateItemFormset(user=request.user.profile, data=request.POST)
Think those two lines need to be reversed.

Django/Pillow - Image resize only if image is uploaded

I'm able to upload an image and resize it, but if I submit the form without images I get this error
The 'report_image' attribute has no file associated with it.
What should I do if no image is uploaded?
This is my models.py
class Report(models.Model):
options = (
('active', 'Active'),
('archived', 'Archived'),
)
category = models.ForeignKey(Category, on_delete=models.PROTECT)
description = models.TextField()
address = models.CharField(max_length=500)
reporter_first_name = models.CharField(max_length=250)
reporter_last_name = models.CharField(max_length=250)
reporter_email = models.CharField(max_length=250)
reporter_phone = models.CharField(max_length=250)
report_image = models.ImageField(_("Image"), upload_to=upload_to, null=True, blank=True)
date = models.DateTimeField(default=timezone.now)
state = models.CharField(max_length=10, choices=options, default='active')
class Meta:
ordering = ('-date',)
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
img = Image.open(self.report_image.path)
if img.height > 1080 or img.width > 1920:
new_height = 720
new_width = int(new_height / img.height * img.width)
img = img.resize((new_width, new_height))
img.save(self.report_image.path)
def __str__(self):
return self.description
I found the solution. Needed to add this check before the actual resize.
if self.report_image:
This way, if no image has been uploaded it will just ignore the resize and proceed without it.
This is the new relevant part:
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
if self.report_image: #check if image exists before resize
img = Image.open(self.report_image.path)
if img.height > 1080 or img.width > 1920:
new_height = 720
new_width = int(new_height / img.height * img.width)
img = img.resize((new_width, new_height))
img.save(self.report_image.path)

Django - [Errno 2] No such file or directory error: when attempting to save an uploaded file to a dynamic url

Models.py:
class Enterprise(models.Model):
name = models.CharField(max_length = 100)
def __str__(self):
return f"{self.id}_{self.name}"
class Client(models.Model):
name = models.CharField(max_length = 100)
def __str__(self):
return f"{self.id}_{self.name}"
class Engagement(models.Model):
name = models.CharField(max_length = 100
def __str__(self):
return f"{self.id}_{self.name}"
class StockCount(models.Model):
name = models.CharField(max_length = 100)
def __str__(self):
return f"{self.name}"
class InventoryList(models.Model):
UploadedFile = models.FileField(_('Upload Inventory Listing'), upload_to = file_upload_location, validators=[validate_file_extension], max_length = 500)
enterprise = models.ForeignKey('Enterprise', on_delete=models.CASCADE, related_name = 'inventorylists')
client = models.ForeignKey('Client', on_delete=models.CASCADE, related_name = 'inventorylists')
engagement = models.ForeignKey('Engagement', on_delete=models.CASCADE, related_name = 'inventorylists')
stockcount = models.ForeignKey('StockCount', on_delete=models.CASCADE, related_name = 'inventorylists')
views.py:
def upload(request):
if request.method == 'POST':
form = InventoryListForm(request.POST, request.FILES)
if form.is_valid():
# file is saved
list = form.save(commit = False)
list.enterprise = Enterprise.objects.get(pk = 1)
list.client = Client.objects.get(pk = 1)
list.engagement = Engagement.objects.get(pk = 1)
list.stockcount = StockCount.objects.get(pk = 1)
list.save()
return HttpResponse(f'You have just made a post request - {list.id}')
else:
return render(request, "observe/upload.html", {"form": form})
else:
return render(request, "observe/upload.html", {"form": InventoryListForm()})
forms.py:
class InventoryListForm(ModelForm):
class Meta:
model = InventoryList
exclude = ['enterprise', 'client', 'engagement', 'stockcount']
def __init__(self, *args, **kwargs):
super(InventoryListForm, self).__init__(*args, **kwargs)
upload_to callable function:
def file_upload_location(instance, filename):
ext = filename.split('.')[-1]
# return f"{instance.enterprise}/{instance.client}/{instance.engagement}/{instance.stockcount}/{filename}"
# return f"{filename}"
FileType = '\\Inventory List'
name = str(filename)
path = os.path.join(str(instance.enterprise), str(instance.client), str(instance.engagement), str(instance.stockcount))
# return f"{path}/{filename}"
# return path
print(f"The path is {path}")
# return f"{path}/"
# return '{0}/{1}/{2}/{3}/{4}'.format(str(instance.enterprise), str(instance.client), str(instance.engagement), str(instance.stockcount), filename)
return os.path.join("%s" % str(instance.enterprise), "%s" % str(instance.client), "%s" % str(instance.engagement), "%s" % str(instance.stockcount), filename)
I have tried multiple variations of the callable functions (as can be seen above from the commented out portions of the function), but I still am getting this error. What is interesting is that when it is the first time I upload the file and submit the form, it works. However, the second time I try, it gives me this errno2 error.
The full traceback is as follows:
[Errno 2] No such file or directory: 'C:\Users\bilal\Desktop\Inventory Observation Mobile Responsive Web Application\Inventory-observation-mobile-responsive-web-application\inventoryobservation\files\1_RSM Canada\PK752_Nuvera Corp\FY 2021_Prospectus work\London Count\Monthly_Sales_Reporting_Template_Tool_Start.xlsm'
It appears as though my actual solutions works for some excel files and not for others, and based on further inspection of the excel files, there doesn't appear to be anything different about the excel files that I am able to successfully upload and the ones that I am not able to upload.
Try to Use this :-
UploadedFile = models.FileField(_('Upload Inventory Listing'), upload_to = 'file_upload_location', validators=[validate_file_extension], max_length = 500)
instead of :-
UploadedFile = models.FileField(_('Upload Inventory Listing'), upload_to = file_upload_location, validators=[validate_file_extension], max_length = 500)
What i've edited :- I have added comas on 'file_upload_location'.
Try to Use it .

Django ValueError when trying to save ManyToMany Values from a Form

I get the error "" needs to have a value for field "dataset" before this many-to-many relationship can be used." when trying to assign values to a ManyToMany field in my views. I've looked at many related questions here on SO that say I must save my Dataset object first. I think I am doing that...what is going wrong?? My database already contains four Subject items.
models.py
class Subject(TimeStampedModel):
subject_type = models.CharField(max_length=128, blank=False)
def __unicode__(self):
return self.subject_type
class Dataset(TimeStampedModel):
dataset_id = models.CharField(max_length=256)
dataset_doi = models.CharField(max_length=15)
dataset_name = models.CharField(max_length=256, blank=False)
dataset_description = models.TextField(blank=False)
lab = models.CharField(max_length=256, blank=False)
biological_sample = models.CharField(max_length=256, blank=False)
subject_type = models.ManyToManyField('Subject', related_name='datasets', blank=True)
date_collected = models.DateField(blank=True)
collection_facility = models.ManyToManyField('CollectionFacility', related_name='datasets', blank=True)
processing_notes = models.TextField(blank=True)
release_date = models.DateField()
release_asap = models.BooleanField()
pdb_code = models.CharField(max_length=256, blank=True)
publication_link = models.URLField(blank=True)
def create_name(self):
self.dataset_name = "%s %s" % (self.biological_sample, self.lab)
def save(self, *args, **kwargs):
self.dataset_id = self.id
def __unicode__(self):
return "%s : %s" % (self.dataset_name, self.dataset_id)
forms.py RegistrationForm:
class RegistrationForm(forms.Form):
subject_type = forms.ModelMultipleChoiceField(
label="Subject",
queryset = Subject.objects.all(),
widget=forms.CheckboxSelectMultiple(),
required = True,
)
views.py
def create_registration(form):
dataset = Dataset()
dataset.DOI = "preUpload"
dataset.lab = form.cleaned_data['lab']
dataset.biological_sample = form.cleaned_data['sample']
dataset.resource_type = form.cleaned_data['dataset_type']
dataset.dataset_description = form.cleaned_data['dataset_description']
dataset.date_collected = form.cleaned_data['date_collected']
dataset.release_date = form.cleaned_data['release_date']
dataset.release_asap = form.cleaned_data['release_asap']
if form.cleaned_data['pdb_code']:
dataset.pdb_code = form.cleaned_data['pdb_code']
if form.cleaned_data['publication_link']:
dataset.publication_link = form.cleaned_data['publication_link']
dataset.create_name()
dataset.save() # I don't think this save is working?
subjects = form.cleaned_data['subject_type']
dataset.subject_type = [x for x in subjects]
for facility in form.cleaned_data['facility']
dataset.collection_facility.add(facility)
dataset.save()
return dataset
def registration_submit(request):
registration_form = RegistrationForm(request.POST)
if registration_form.is_valid():
registration = create_registration(registration_form)
.......
You forgot to call the original save() in the overriden Dataset.save() method.
def save(self, *args, **kwargs):
self.dataset_id = self.id
super(Dataset, self).save(*args, **kwargs)