I have a profile app, where users can upload a profile picture. I save the picture with the user's username eg. ifakih.jpg. If that file already exists, and they want to change their profile picture, I delete the old one and replace it with the new one. I can see the change in my directory. The old ifakih.jpg is replaced with the new one. However, my website still uses the old image. If I go to the admin and check the imagefield for that user, it points to the correct directory and image, but the content is wrong.
Models.py:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
name = models.CharField(max_length=64,blank=True)
profilePic = models.ImageField(blank=True, null=True, upload_to= path_and_rename)
phoneNumber = models.CharField(max_length=12,blank=True)
streetAddress = models.CharField(max_length=64,blank=True)
#receiver(pre_delete, sender=Profile)
def post_delete(sender, instance, **kwargs):
"""
Deleting the specific image of a Post after delete it
"""
if instance.profilePic:
if os.path.isfile(instance.profilePic.path):
os.remove(instance.profilePic.path)
#receiver(pre_save, sender=Profile)
def post_update(sender, instance, **kwargs):
"""
Replacing the specific image of a Post after update
"""
if not instance.pk:
return False
if sender.objects.get(pk=instance.pk).profilePic:
old_image = sender.objects.get(pk=instance.pk).profilePic
new_image = instance.profilePic
if not old_image == new_image:
if os.path.isfile(old_image.path):
os.remove(old_image.path)
else:
return False
This sounds like a problem that comes from the browser caching images.
To see whether it is related to that, try reloading with STRG + F5 to ignore cached files (you can disable the browser cache in the network tab).
You could solve that problem in two ways:
1) You disable caching for your profile pictures so that the browser always loads the image and does not cache at all. This leads to more traffic on your server and also a longer load time of your site. (NOT recommended)
2)You change the file saving behaviour and allow different filenames. This way the browser will load the image for the first request and then can use it's cache. An ImageField will also generate you a unique name while saving. (Preferred)
Related
I'm Currently developing a app with a ManyToMany ImageField Relantionship . I want to have the ImageField save all images to a specific folder based on the ID of the Relantionship.
I want to have something like this.
class PostImages(models.Model):
image = models.ImageField(upload_to='Post_Images/post/' + post.id)
class Post(models.Model):
images = models.ManyToManyField(PostImages)
How do I access the post.id to do this ? I mostly want to do this for organization purposes right now cause its on my local machine but also see no reason to change it when I deploy.
E.g. based on FileField^ but the same you can use for ImageField:
def get_file_path(instance, filename):
return instance.created.strftime("folder/%Y/%m/%d/") + instance.post.id
bfile = models.FileField(upload_to=get_file_path, null=True)
I have a form that takes in user data like bio, profile picture, gender, etc. and upon submission either creates this new row about the user or updates the existing row. This will only work if the user uploads an image. If no image is uploaded for the profile picture, then the form doesn't submit. How can I make it so that if the user didn't upload a profile picture, then it'll keep the user's previous profile picture and still submit?
Here's my code:
class ProfileSettings(UpdateView):
model = Profile
template_name = 'blog/settings.html'
form_class = ProfileForm
success_url = reverse_lazy('blog:settings')
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST, request.FILES)
if form.is_valid():
bio = form.cleaned_data['bio']
gender = form.cleaned_data['gender']
avatar = form.cleaned_data['avatar']
Profile.objects.update_or_create(user=self.request.user, defaults={'avatar':avatar, 'bio':bio, 'gender':gender})
return HttpResponseRedirect(self.success_url)
I'll give you the quick and dirty - 3 places to solve this:
Javascript - make the form aware of what fields are required and pre-fill if the username already exists (out of scope from your question but just throwing it out there)
In the API endpoint (this seems to be the approach you are going for)
In your model (implement a custom save function that looks to see if new, and compare initial value to subsequent value)
I'll dump options 1 and 3 because they aren't pertinent to your question as asked. I'm assuming user is unique per profile. And I'm assuming that currently the field avatar is required. If you set that to not required then the form post should allow a null value for avatar - How to make FileField in django optional?. You may be thinking, but I don't want that field to be possibly blank - you could always enforce that the first time the post is made that the field is set via the API endpoint itself. If you made that field optional then the form would post but you may want to be more explicit with .update_or_create by actually checking to see if the object already exists and if so require the field or if not confirm that field is set.
I have a system where users can upload cover photos to playlists. The playlist model is as following:
class Playlist(models.Model):
.
.
image = models.ImageField(upload_to='media/playlistimages')
.
.
The upload mechanism is as follows: Users chooses a photo, I upload it to a temporary model, and show it to the user. If the user chooses to save the photo, I proceed and save the image. Preview images are kept in a different model
class PreviewImage(models.Model):
.
.
image = models.ImageField(upload_to='media/previewimages')
.
.
Not to upload the image twice, when the user first chooses the photo, I upload it and save in the preview image model. Then, if the user proceeds to save the playlist, I only send the preview image id to the server and save the image in that object to the playlist as follows:
playlist.image = previewImage.image
playlist.save()
The problem is, the image is at first uploaded to the previewimages folder, and when I save the playlist's image as in the example above, it is still in that folder. How can I move this file to playlistimages folder while saving?
For doing what you want, you can overwrite the PlayList form's 'save' method. Something like:
def save(self, commit=True):
temp_file_id = self.cleaned_data.get('preview_image_id', False)
if temp_file_id:
try:
temp_file = PreviewImage.objects.get(pk=temp_file_id)
instance = super(PlayListForm, self).save(commit)
instance.image.save(
os.path.basename(temp_file.file.path),
temp_file.file.file,
commit
)
# If you want to erase the file from its previous location,
# as well as the PreviewImage object do the following
os.remove(temp_file.file.path)
temp_file.delete()
# Finally return saved instance
return instance
except PreviewImage.DoesNotExist:
# handle this the way it fits your needs...
except Exception as e:
raise e;
else:
# handle this the way it fits your needs...
This code is untested, it is only meant as a general idea.
Hope this helps you.
I wrote an image upload form which handles file and URL uploads. This is a model form which commits to the database an unpublished image.
class UnpublishedImage(Model(20)):
picture = ImageField(help_text=_('Unpublished picture'), upload_to=settings.UNPUBLISHED_PICTURE_UPLOAD_TO)
That Model(20) gives each model a pid field (20 random slug chars), which I use as a public ID for my models.
The unpublished images work just fine, but now I want to use them, that is, I want to publish them.
class Look(Model(20)):
user = OneToOneField(get_user_model(), editable=False)
title = CharField(max_length=40)
description = TextField(max_length=160)
#image = OneToOneField(UnpublishedImage)
To make this clear, it works in two steps:
The user uploads an image (unpublished)
The next form shows the image and allows to add a description, title, etc.
Now, I can't use OneToOneField to the UnpublishedImage model because I want to delete it from the unpublished table (and storage) as soon as the image is published. How do you recommend doing this?
I have tried ImageField, but I don't know how to give the image to the form.
Note that there's a third form for retrieving unpublished images, so you can use that.
class UnpublishedImagePublishForm(Form):
image = CharField()
def clean_image(self):
# Get the unpublished object
try:
unpublished = UnpublishedImage.objects.get(pid=self.cleaned_data['image'])
except UnpublishedImage.DoesNotExist:
raise ValidationError(_("Image not found"))
return unpublished
This way I can get the image:
# Get the unpublished image
unpublished = UnpublishedImagePublishForm(request.DATA)
if not unpublished.is_valid():
return Response(unpublished.errors, status=HTTP_422_UNPROCESSABLE_ENTITY)
# Get the unpublished image instance
image = unpublished.cleaned_data['image']
Thanks in advance.
I'm trying to create some kind of 'media manager' model which will allow the user to upload different kings of media (images, swfs, pdfs) similar to the way WordPress does. My media model looks something like this:
class Media(models.Model):
id = models.AutoField(primary_key=True)
url = models.FileField(upload_to="uploads")
mimetype = models.CharField(max_length=64, editable=False)
created = models.DateTimeField(auto_now_add=True, editable=False)
When a user uploads a file, I want to first determine what kind of file it is and if it's an image, manipulate it further. I want to be able to to specify the dimensions (crop) of the uploaded image via a view, so when I call the .save() method, the model will resize and crop the image, upload it and populate the database with the url to the file.
I also want to ensure that the upload of the image is done AFTER the post processing (cropping etc), I have no need to keep the original file.
So the question I am asking is how do I got about passing parameters to the FileFields save method (so I can pass dynamic properties for image post processing) and how can I ensure the post processing is done BEFORE the image is uploaded?
Edit: When I say before the image is uploaded, I mean before it's saved to it's final destination. I understand the image has to go int othe tmp folder first before I can post process it. Sorry for the misleading question.
Hope someone can help :)
You cannot do anything before the image is uploaded (because you have nothing to work with).
But if you want modify the image before saving it into db, you can do it in model's save() method, before calling parent's save()
If you are uploading it via admin, override method save_model() in admin.py, ie:
def save_model(self, request, obj, form, change):
file = request.FILES.get('url') # name of field
if file:
# proceed your code
return super(AdminClassName, self).save_model(request, obj, form, change)
Here is my code how to change file before actually upload it. I think you should get my idea
from django.core.files.uploadedfile import InMemoryUploadedFile
#....
#some form
def clean_avatar(self):
av = self.cleaned_data['avatar']
resized = make_avatar(av,65) # My custom function than returns image
return InMemoryUploadedFile(resized, av.field_name, av.name, av.content_type, resized.len, av.charset)
You can read django code for InMemoryUploadedFile "documentation".
And in your resize/crop function you should use StringIO not file to save result
How could the processing be done before the image is uploaded? That doesn't make sense. The server doesn't have any access to the file until you upload it.
If you actually want to handle the file before it's saved, you can write a custom upload handler. You can test there whether the file is an image, then crop it appropriately, before saving. (You'll need the Python Imaging Library for both of those tasks.)