Cannot upload an image in django using ImageField - django

I am writing my first django app that uses the ImageField and I am having
difficulty. The problem is that my images are not uploading. I have looked at
as many examples that I can find. And I'm not sure what's going wrong here.
I am trying to verify that my photos are uploading by looking in the location
of the upload_to directory. When the form is displayed in the web page the
correct upload file button is displayed. When I hit submit, the code below executes,
but no images are ever uploaded.
Based on the upload_to, I am expecting to see images uploaded to see images under either:
myproject/photos or myproject/media/photos correct?
Am I doing anything obvious wrong here? How do I get my images to upload?
--------------settings.py-------------
MEDIA_ROOT = '/home/me/django_projects/myproject/media/'
MEDIA_URL = '/media/'
--------------model.py-------------
class Person(models.Model):
lastName = models.CharField(max_length=20)
firstName = models.CharField(max_length=20)
image = models.ImageField(upload_to='photos', blank=True, null=True)
# save executes but no image is saved.
# Because images are uploaded along with a new entry, I needed a special
# work around to get the self.id
def save(self):
for field in self._meta.fields:
if field.name == 'image':
if self.id is not None:
#save image now
field.upload_to = 'photos/%d' % self.id
else:
#Save image later
saveImageLast = True
super(Customer, self).save() # should create self.id if not already
if saveImageLast == True:
field.upload_to = 'photos/%d' % self.id
super(Customer, self).save()
print "save complete" #prints, but no image ...?
--------------forms.py-------------
class PersonForm(ModelForm):
class Meta:
model = Person
fields = ( 'lastName', 'firstName', 'image' )

from django documentation, i think this can help (in the past this helped me):
Firstly, in order to upload files, you'll need to make sure that your
element correctly defines the enctype as "multipart/form-data"
<form enctype="multipart/form-data" method="post" action="/foo/">

In your view where you create an instance of the form with post data, ensure you have provided request.FILES
form = PersonForm(request.POST, request.FILES)

This is a bit late, but 'upload_to' is not a method. It's an attribute that represents the relative path from your MEDIA_ROOT. If you want to save an image in the folder 'photos' with the filename self.id, you need to create a function at the top of your model class. For instance:
class Person(models.Model):
def file_path(instance):
return '/'.join(['photos', instance.id])
image = models.ImageField(upload_to=file_path)
Then when you are actually saving your image you would call:
person = Person(firstName='hey', lasteName='joe')
person.image.save(ImageObject.name, ImageObject)
More on the image file objects here.
More on upload_to here.

Related

create pdf with each post django

Currently working on a django social media application where next to posting every post to the feed, the information of each upload should create a pdf document, containing caption, image, created_at and image_id.
I´ve put the canvas into the upload functions, so that both will be created on the same click. So far, i get a pdf (can't get the attributes from the post into the pdf tho) and the post is uploaded just fine.
How do I get the posted data into the pdf?
And how do save that pdf to a folder within the project instead of starting an automatic download? The user should not be able to notice the pdf converting. It is just for back office - but very necessary due to the social media website being a part of a big installation. So how do I get these pdfs?
Here is the code:
views.py
def upload(request):
if request.method == 'POST':
#user = request.user.username
image = request.FILES.get('image_upload')
caption = request.POST['caption']
new_post = Post.objects.create( image=image, caption=caption)
new_post.save()
#create pdf
buffer = io.BytesIO()
p = canvas.Canvas(buffer)
p.drawString(100, 100, "Hello world.")
p = request.FILES.get('post_pdf')
p.drawText('caption')
p.drawImage('image')
p.showPage()
p.save()
buffer.seek(0)
return FileResponse(buffer, as_attachment=True, filename='hello.pdf')
return redirect('/')
else:
return redirect('/')
models.py
class Post(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4)
image = models.ImageField(upload_to='post_images')
caption = models.TextField(max_length=300)
created_at = models.DateTimeField(auto_now_add=True)
number_of_likes = models.IntegerField(default=0)
number_of_dislikes = models.IntegerField(default=0)
#interaction_count = models.IntegerField(default=0)
#engagement_count = models.IntegerField(null=True)#number_of_dislikes + number_of_likes
def __str__(self):
return self.caption
To add the value of Post.caption into the pdf, use the value of new_post.caption, change this:
p.drawText('caption')
for this:
p.drawText(new_post.caption)
Same for other fields.
This is not as hard as it seems,
so Let's see if you are successful in creating a pdf and now you have to store it in background instead of downloading.
file_name = request.FILES["file_name"]. #suppose file_name is file name
file_name = default_storage.save(rf"{basePath}/media/whatsapp/file_name.pdf", file_name) #{basePath}/media/whatsapp/ is the path name where we want it to be stored

Approaches for adding multiple image on a post Django

I am working on a platform where I need to allow users to upload multiple images in one post.
I want to keep it as simple as possible, so that a person wouldn't have to refresh the page to upload each image, or create and save a post before adding images.
If a user could delete or reorder images it would be nice
Can you give me advice on how to do it properly?
I am using django , postgres and here's what I have done so far .
On my models.py -
class ImagePost(models.Model):
user = models.ForeignKey("profiles.HNUsers", on_delete=models.DO_NOTHING)
image = OptimizedImageField("Post Image", blank=True, null=True)
timestamp = models.DateTimeField("Timestamp", blank=True, null=True, auto_now_add=True)
text = models.TextField("Description text", blank=True)
class Meta:
verbose_name_plural = "Image Posts"
It can take one image just fine . what should I change to make it multi upload post
On my views.py this is what I have done so far -
#api_view(['POST'])
#permission_classes((permissions.AllowAny,))
def image_post(request):
if request.method == 'POST':
data = request.data
print(data)
serializer = ImagePostSerializer(data=data)
if serializer.is_valid():
serializer.save()
print("image object saved")
try:
image_post_object = ImagePost.objects.filter(user__id=data['user']).order_by('-timestamp')[0]
print(image_post_object)
try:
post = Posts()
post.user = HNUsers.objects.get(id=data['user'])
post.image_url = image_post_object.image.url
post.type = 'I'
post.category = data['category']
post.created_on = image_post_object.timestamp
post.text = image_post_object.text
save_post = post.save()
post_id = post.pk
try:
user = HNUsers.objects.get(pk=data['user'])
if user.user_type == 'HN':
payload = {
"user_name": user.full_name,
"image_url": user.profile_img_url,
"post_id": post_id,
"notification_type": "hn"
}
print(payload)
broadcast_notification('all', payload, 1)
except HNUsers.DoesNotExist:
print("user_id_does_not_exist")
print("post object created")
except Posts.DoesNotExist:
print("Failed - post creation failed")
except HNUsers.DoesNotExist:
print("Failed - user object not found")
except ImagePost.DoesNotExist:
print("Failed - image object not found")
return Response(serializer.data, status=status.HTTP_200_OK)
Any advice is really appreciated.
I am not sure if this can help, but why you dont use more than one table to store images in DB:
class Images(models.Model):
user = models.ForeignKey("profiles.HNUsers",
on_delete=models.DO_NOTHING)
image_post = models.ForeignKey(ImagePost, on_delete=models.CASCADE)
image = OptimizedImageField("Post Image", blank=True, null=True)
Now you have conected multiples images to a post and a user.
Hope this helps a bit...
Check this excellent django version of jQuery-File-Upload :
https://github.com/sigurdga/django-jquery-file-upload
Some features:
Drag and drop files
Select multiple files
Cancel upload
Delete uploaded file
You can avoid a lot of code repetition and add multiple images for a model by creating an intermediate model which will handle mapping between your image and the model. Create proper binding like one to one , you can look at this tutorial

How to upload and view images in django

models.py
class FileUpload(models.Model):
File_Name = models.CharField(max_length=255, blank=True)
File_path = models.FileField(upload_to='')
Description = models.CharField(max_length=255, blank=True)
Upload_Date = models.DateTimeField(auto_now_add=True)
forms.py
class FileUploadForm(forms.Form):
class Meta:
model = FileUpload
File_Name = forms.CharField(label="File Name",max_length=255)
Description = forms.CharField(label="Description", max_length=255)
I'm new in Django.I need help. How to upload images in the database and view those images? Thanks in advance!
here paths are stored in database and images are stored in a folder. But I don't need that. I want to save images and path to the database and I need to view that image. Please help!
views.py:
def uploadfile(request):
print('inside upload logic')
if request.method == 'POST':
form = FileUploadForm(request.POST, request.FILES)
if form.is_valid():
# ImageUpload(request.FILES['File_Name'])
myfile = request.FILES['File_Name']
fs = FileSystemStorage()
filename = fs.save(myfile.name, myfile)
uploaded_file_url = fs.url(filename)
newdoc = FileUpload(File_Name=myfile.name, File_path=uploaded_file_url, Description=request.POST['Description'])
newdoc.save()
#return HttpResponse("File uploaded successfuly")
return render(request, 'Login/fileupload.html')
else:
form = FileUploadForm()
return render(request, 'Login/fileupload.html', {
'form': form
})
You normally shouldn't store the image data in your database. If you need to upload and store images, use the ImageField or FileField and follow the instructions from the docs to save the image. The only thing you need to do is:
form = FileUploadForm(request.POST, request.FILES)
if form.is_valid():
uploaded_file = FileUpload(
File_path=request.FILES['File_path'], # or whatever you've called the file input
File_name=form.cleaned_data['File_Name'],
Description=form.cleaned_data['Description'])
uploaded_file.save()
It would be easier to use a ModelForm in your case, then you only need to save the form:
if form.is_valid():
form.save()
This will automatically save the file in the correct way. No need to do the saving manually like you are doing.
To view the image is as simple as this:
file_upload = FileUpload.objects.get(id=34)
file_url = file_upload.File_path.url # url relative to `MEDIA_ROOT`
# or in a template
{% load static %}
{% get_media_prefix %}{{ file_upload.File_path.url }}
If you really need to store the images as binary blobs to your database (but beware that it almost never makes sense to do so), use Django's BinaryField, as described here.
This also means you will have to handle transforming the image back and forth from a binary blob to a proper image file. Consider also storing the content type (image/jpg or image/png or image/webp) since you will need that to properly re-create the file.

Django get renamed uploaded image url

I am working on a project that will allow the user to upload image. The uploaded image will later on displayed and be passed to another form. To do this, I need to get the image url of the uploaded image. Here is my code:
def inputImage(request):
if request.method == 'POST':
form = ImageDetailsForm(request.POST, request.FILES)
if form.is_valid():
form.save()
message = "The image was successfully uploaded!"
imageName = str(request.FILES['image'].name)
imageURL = settings.MEDIA_URL + "/" + imageName
return render(request,'success.html', {'message': message, 'image': imageURL})
The code is working, however a problem would occur if the user uploads a file with an existing filename at the storage. To avoid conflict, Django automatically renames the file but the line
imageName = str(request.FILES['image'].name)
only returns the original filename of the uploaded image. I have also tried to use
imageName = str(form.cleaned_data['image'].name)
but still no changes. It returns "/media//1.png" instead of "/media//1_0rnKMaT.png"
Any ideas on how to get the URL of the current upload in Django?
Edit:
here is my models.py:
class ImageDetails(models.Model):
image = models.ImageField(null=True)
and my forms.py
class ImageDetailsForm(forms.ModelForm):
class Meta:
model = ImageDetails
fields= ('image')
widgets = {
'status': forms.HiddenInput(),
}
You can access the saved model instance through form.instance, so you should be able to get the name of the saved file with form.instance.image_field_name.name where image_field_name is the name of the image field in your model.

Changing save location of file for a model inside a view

I have the following model.
class Image(models.Model):
customer = models.ForeignKey(Customer, related_name='images')
image = models.ImageField(upload_to='/pictures/', verbose_name='Image')
Each time user add a new Image I want it to go under pictures/customer.id/custom_filename
When I was using local filesystem, that was easy. I used a function that handled file chunks upload with a new name and returned the new path. But now I want to use S3 to store my files. So I am using django-storages. I did the following tests:
testmodel
class TestModel(models.Model):
name = models.CharField(max_length=10)
logo = models.ImageField(upload_to='pictures/')
when I do this in my view
def index(request):
form = TestModelForm(request.POST or None, request.FILES or None)
if request.method == 'POST':
if form.is_valid():
print 'posting form'
model = form.save(commit=False)
print model.name
print model.logo.url
model.save()
and the image is uploaded as it should under mybucket.s3.amazon.com/pictures/logoname.jpg
But if I change the file name by some way like
def index(request):
form = TestModelForm(request.POST or None, request.FILES or None)
if request.method == 'POST':
if form.is_valid():
print 'posting form'
model = form.save(commit=False)
print model.name
filename = str(request.FILES['logo']).split('.')[0]
extension = str(request.FILES['logo']).split('.')[1]
path = '%d%d%d_%s_%d.%s' %(datetime.now().year, datetime.now().month, datetime.now().day, filename, models_no+1, extension)
model.logo = path
print model.logo.url
model.save()
i get a new url which is mybucket.s3.amazon.com/newlogoname.jpg (correct since I didn't user pictures in the new path) but the file is not uploaded. Must I do it manually using boto? I guess it's the only way since folders for each customer (initial example) might not exist and need to be created. What is the correct way to upload images at custom locations/directories for each model?
I tried to call default storage directly to save the image in the location I wanted but didn't work
default_storage.save('pictures/one.jpg', ContentFile(request.FILES['logo']))
The key is created (the folder and the file) but the image is empty. I think using cloud storage in a flexible way is very difficult :(
You can pass a callable as the upload_to named argument, in your model definition (so you actually don't have to do this on the view level). To make it clear, try doing something like this:
class Image(models.Model):
customer = models.ForeignKey(Customer, related_name='images')
image = models.ImageField(upload_to=self.generate_upload_path, verbose_name='Image')
def generate_upload_path(self, filename):
return os.path.join('/pictures/'+str(self.customer.id), filename)