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)
Related
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
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
I have figured out a lot today and got my class views run. But I want to change my DetailViews to ListViews what works well. But I can't set a queryset to filter the ListViews properly like how I filtered them in the DetailsViews.
I always get that error:
"'WSGIRequest' object has no attribute 'thema'"
I will post the code so you can see what I am trying to do :-)
models.py
class Thema(models.Model):
themengebiet = models.CharField(max_length=350)
beschreibung = models.TextField()
themen_logo = models.FileField(max_length=350, upload_to="logos", default='default.jpg')
erstellt_am = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.themengebiet
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
img = Image.open(self.themen_logo.path)
if img.height > 300 or img.width > 300:
output_size = (300, 300)
img.thumbnail(output_size)
img.save(self.themen_logo.path)
class Thread(models.Model):
thema = models.ForeignKey(Thema, on_delete=models.CASCADE)
titel = models.CharField(max_length=350)
author = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
erstellt_am = models.DateTimeField(default=timezone.now)
thread_logo = models.ImageField(upload_to="logos", default='default.jpg')
#def get_absolute_url(self):
#return reverse('forum:thread-page', kwargs={'pk': self.thema.id})
def __str__(self):
return self.titel
class Posting(models.Model):
thread = models.ForeignKey(Thread, on_delete=models.CASCADE)
titel = models.CharField(max_length=350)
erstellt_am = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
inhalt = models.TextField()
def __str__(self):
return self.titel
views.py
class ThemenView(ListView):
template_name = 'forum/posts_original.html'
context_object_name = 'all_themen'
ordering = ['-erstellt_am']
paginate_by = 5
def get_queryset(self):
return Thema.objects.all()
class ThreadView(ListView):
model = Thread
context_object_name = 'all_threads'
template_name = 'forum/thread.html'
success_url = reverse_lazy('forum:posts_original')
ordering = ['-date_posted']
paginate_by = 5
def get_queryset(self):
return Thread.objects.filter(thema=self.request.thema)
i found the solution. sorry for bothering you guys: def get_queryset(self): thema = get_object_or_404(Thema, pk=self.kwargs.get('pk')) return Thread.objects.filter(thema=thema).order_by('erstellt_am')
forms.py
class MySelect(forms.Select):
def __init__(self, *args, **kwargs):
self.variations = kwargs.pop('variations')
super(MySelect, self).__init__(*args, **kwargs)
def render_option(self, selected_choices, option_value, option_label):
return '<option whatever>...</option>'
class CartItemForm(forms.ModelForm):
class Meta:
model = CartItem
fields = (
'variation',
'width',
'height',
'quantity',
)
widgets = {
'variation': MySelect(variations=self.variation_query)
}
def __init__(self, *args, **kwargs):
product = kwargs.pop('product')
try:
cart = kwargs.pop('cart')
self.cart = cart
except:
pass
super().__init__(*args, **kwargs)
variation_field = self.fields['variation']
variation_field.queryset = Variation.objects.filter(
product=product
)
self.variation_query = Variation.objects.filter(
product=product
)
def save(self):
cart_item = super().save(commit=False)
cart_item.cart = self.cart
cart_item.save()
return cart_item
Below is where you have to pay attention to.
(in Meta class)
widgets = {
'variation': MySelect(variations=self.variation_query)
}
self.variation_query is from __init__.
How can I do this?
models.py
class CartItem(models.Model):
cart = models.ForeignKey("Cart")
variation = models.ForeignKey(Variation)
# 벽화 너비
width = models.PositiveIntegerField(
default=1,
validators=[MinValueValidator(1)],
)
class Product(TimeStampedModel):
name = models.CharField(max_length=120, unique=True)
slug = models.SlugField(null=True, blank=True)
description = models.TextField(max_length=400, blank=True)
is_active = models.BooleanField(default=True)
place_category = models.ForeignKey(
"PlaceCategory",
related_name="products_by_place", # category.products_by_place.all()
)
subject_category_set = models.ManyToManyField(
"SubjectCategory",
related_name="products_by_subject", # category.products_by_subject.all()
)
# 벽화 높이
height = models.PositiveIntegerField(
default=1,
validators=[MinValueValidator(1)],
)
quantity = models.PositiveIntegerField(
default=1,
validators=[MinValueValidator(1)],
)
class Variation(TimeStampedModel):
COLOR_CHOICES = (
('black', '흑백'),
('single', '단색'),
('multi', '컬러'),
)
price = models.DecimalField(
decimal_places=0,
max_digits=15,
blank=True,
null=True,
)
product = models.ForeignKey(Product)
color = models.CharField(
max_length=10,
choices=COLOR_CHOICES,
)
is_active = models.BooleanField(default=True)
That's not a thing you would do in Meta. You need to do the whole thing in __init__.
You're already doing that in fact, so I don't know why you want to override Meta at all.
When I try to load an admin edit page with image inliner, I get a weird object which crashes my page. This thing goes last after all my images are loaded.
What can it be?
Code
models.py
class Image(BaseImage):
article = models.ForeignKey(Article, verbose_name=u'Новость', null=True)
in_preview = models.BooleanField(u'Отображать в превью', default=False)
weight = models.IntegerField(u'Порядок', default=0)
class Meta:
verbose_name = u'Изображение'
verbose_name_plural = u'Изображения'
ordering = ('weight',)
def get_upload_to(self, filename):
return os.path.join('articles', 'image', 'image_file', filename)
def list_thumbnail_tag(self):
source = self.image_file
if source:
thumbnail = get_thumbnailer(source).get_thumbnail({'size': (100, 100), 'crop': True})
return '<img src="{}">'.format(thumbnail.url)
list_thumbnail_tag.short_description = 'Превью'
list_thumbnail_tag.allow_tags = True
class BaseImage(models.Model):
image_file = models.ImageField(u'Файл', upload_to='uploads')
image_alt = models.CharField(u'Атрибут Alt', max_length=255, blank=True)
image_title = models.CharField(u'Название', max_length=255, blank=True)
def __str__(self):
return os.path.basename(self.image_file.path)
def get_upload_to(self, filename):
return os.path.join('images', filename)
class Meta:
abstract = True
verbose_name = u'Изображение'
verbose_name_plural = u'Изображения'
It's like the error message says: the __str__ method on BaseImage calls image_file.path, but the particular instance you're looking at has no image_file set.
You should use a value that doesn't depend on that field being set, or deal with that case somehow.