How do I set uploaded image back to default image when deleted? - django

I have a simple blog app, when I update an article and remove photo I want it to use default photo.
it selects that image on create but when updating it throws an error.
here's my Models.py code.
image = models.ImageField(
upload_to="uploads/articles/",
null=True,
blank=True,
default="uploads/articles/noimage.png",
)
the error I get when I remove image during update.
Error during template rendering
The 'image' attribute has no file associated with it.
<img class='article-img' src="{{article.image.url}}" alt="">

You can use Django Signals
on delete or update or create, please read more about it.
It is like run trigger on model for example when update method happen you can check image field if it empty you can add image to it.
solution 2: override save method in django model and apply previous condation
solution 3: make static field using #proparty and check from front end if there is no image .. render this field
solution 4: I'm not sure about it but you can check on_delete=models.SET_DEFAULT

Related

Deal with django ImageField current value displayed in forms

I'm trying to remove the clear checkbox in Django's ImageField and remove the displayed current value of the file. Tha approach I tried is to replace the widget as proposed here How to not render django image field currently and clear stuff? but the result is that I get ValidationError :
"Upload a valid image. The file you uploaded was either not an image or a corrupted image.". Though the validation error the image get's uploaded, but I do not get redirected to the success page and an error is being rendered in the form.
What's the recommended way to remove the current value in the ImageField?
A solution that works for me, though I'm not sure how good is it.
profile_picture = forms.FileField(label='Upload profile picture', widget=forms.FileInput,validators=[validators.validate_image_file_extension], required=False)
I replaced ImageField with FileField and then added the ImageField default validator with FileInput widget and then added 'accept': 'image/*' to that widget, so the select shows only images. In this way I mimic the ImageField, but no error occurs.

Django ClearableFileInput - how to detect whether to delete the file

I'm using Django Crispy Forms for my form with an option to upload an image (ImageField in my Model)
The forms renders as I'd expect, with the checkbox to clear an existing file. However when processing the form submission the 'image-clear' checkbox always gives me a 'None' value.
image_clear = form.cleaned_data.get("image-clear")
print image_clear
In the HTML of the page I notice that the input checkbox doesn't have a value attribute, see:
<input id="image-clear_id" type="checkbox" name="image-clear">
So I wondered if this was the issue, but when I look at the rendering in the Django admin site, the corresponding HTML input field doesn't have a value either - yet it still identifies that the image should be removed.
I should note that if I upload a new image, then this works, it's only the case where I'm removing/clearing the image (and it works in Django admin pages, so assume that means my model definition is ok to allow no image to be attached to the model)
So... in my form processing, how do I detect whether or not the image should be removed or not?
I'm sure I'm missing something simple here - and any help much appreciated.
You shouldn't check the checkbox, but check the value of the file input field. If it is False, then you can delete the file. Otherwise it is the uploaded file. See: https://github.com/django/django/blob/339c01fb7552feb8df125ef7e5420dae04fd913f/django/forms/widgets.py#L434
# False signals to clear any existing value, as opposed to just None
return False
return upload
Let me add here my code that solved the problem - I decided to put this logic to ModelForm.clean():
class Document(models.Model):
upload = models.FileField(upload_to=document_name, blank=True)
class DocumentForm(ModelForm):
def clean(self):
cleaned_data = super(DocumentForm, self).clean()
upload = cleaned_data['upload']
if (upload == False) and self.instance.upload:
if os.path.isfile(self.instance.upload.path):
self.instance.upload.delete(False)

Customize ImageField url/path

I have a Page model that basically describes an HTML page. Pages are then served with URLs, such as http://www.mysite.com/page/1234/ for the page of id (pk) 1234.
I want to be able to add or attach images to my page. Therefore, I would like to use an Image class with a foreign key to a Page object:
class Page(models.Model):
title = ...
content = ...
class Image(models.Model):
page = models.ForeignKey(Page)
image = models.ImageField(...)
Here is my problem: I would like to deliver images to the client with urls of the form:
http://www.mysite.com/images/1234/image_name.jpg, i.e a URL that includes the page id. Also on the server, the paths should reflect the page structure: /path/to/media/images/1234/image_name.jpg
I don't know how to tackle this problem. On one hand, I would like to keep the features of an ImageField related to path formatting. For example when uploading two images with the same name, Django creates two paths ending with "image.jpg" and "image_2.jpg" or so to make the difference between both images.
On the other hand, the upload_to option has limited capability, and I don't know how to insert the page id in the path. Especially, some tricky cases such as uploading an image at the same time a page is created (using the same form), which means a page id should be generated before uploading the image.
Is it reasonably easy to make an image model that would behave as described above? If so, how do I have to modify the Image model to insert the page id in the image path?
I have seen the question Customize save path for ImageField, but it does not address the problem of primary key that might not be assigned.
Thanks.
Actually, a simple function passed as an upload_to parameter works, and there is no problem of non-existing id. So I guess that Django's default behaviour saves the image after saving the parent page model, as I wanted to.
In the Image model:
image = models.ImageField(upload_to=get_image_path)
with the following function:
def get_image_path(instance, filename):
return 'pics/' + str(instance.page.id) + '/' + filename

How to bind an image to an edit form in Django?

I have the following Model:
class Listing(models.Model):
name = models.CharField(max_length=50, verbose_name="Title")
images = models.ManyToManyField('Image')
, with the ManyToManyField linking to this Image class:
class Image(models.Model):
thumb = ImageField(upload_to='images/uploads/')
number = models.PositiveSmallIntegerField()
and a corresponding ModelForm like so:
class ListingEditForm(ModelForm):
image1 = ImageField(required=False, label="Photo 1")
image2 = ImageField(required=False, label="Photo 2")
image3 = ImageField(required=False, label="Photo 3")
class Meta:
model = Listing
exclude = ('images')
The idea is to not limit the number of images that can be associated with a Listing in the backend, but at this time I only need 3 images in the form. Uploading the images works fine, but how would you go about binding the form to a Listing instance so that the images are not 'None' when one views the edit form?
Obviously, this alone won't work, because image1, image2 and image3 are only form fields, and not part of the model:
form = forms.ListingEditForm(instance=listing)
So adding a dictionary as the first parameter seems like the obvious thing to do:
form = forms.ListingEditForm({'image1': ...},instance=listing)
but what should the value of that ... be? And how do I retrieve it from the Listing instance?
I'll answer my own question, even though it's not quite the answer I was looking for. I've looked around, and as far as I know, there is no reliable way in HTML to change the contents of a File input field. So, I could be wrong, but even if you send that information with the request, Django will have no way of showing the information in the field (since it doesn't correspond to a file on the local PC).
So, my solution is simply to send the urls of the images with the request, as one normally would:
return render_to_response('edit.html', {'image1': image1_url, ...})
Then, if this information is present, I use jQuery to place the images next to the file input field in the template, and update it if the user selects a new file. It's not the best, but it works.
I'll still be glad to hear any other solutions.
I would use foreign key relation in Image, and inlineformset_factory for generating the form.
ListingEditForm = inlineformset_factory(Listing, Image, max_num=3, extra=0)
I would also add image name field in Image model. That way user will have indication of uploaded files in form display, and he will also be able to delete images if he whishes so. If you need unlimited uploads you can simply change max_num to 0 and extra to 1.
Of course that way you cannot associate one image with more then one Listing object, but if you need user to be able to delete images that is not recommended anyway.

Django and ImageField Question

Foo (models.Model):
slug = models.SlugField(unique=True)
image = models.ImageField(upload_to='uploads/')
I want to do two things with this:
First of all, I want my image to be forced to resize to a specific width and height after the upload.
I have tried this reading the documentation but seems to getting error:
image = models.ImageField(upload_to='uploads/', height_field=258, width_field=425)
Secondly, when adding an item via admin panel, I want my image's file name to be renamed as same as slug, if any issue arises (like if such named image already exists, add "_" to the end as it used to do.
IE: My slug is i-love-you-guys , uploaded image such have i-love-you-guys.png at the end.
Signals are the answer to both of your questions.
As stated in the docs, the height_field and width_field are names of fields where to store the original image's height and width -- not to coerce the image to a certain size. I think the best way to handle what you want to do is to use either the pre_save or post_save signal to resize the image using PIL. You may also want to check out sorl. In fact, you can use the sorl's thumbnail in your signal to create the new image.
To rename the filename, also use a signal.