Changing save location of file for a model inside a view - django

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)

Related

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.

How to upload files in Django and save them in a different location depending on the format? (jpeg and doc)

How to upload files in Django and save them (and take other actions in the signal - post_save) in a different location depending on the format? (jpeg and doc)
def upload(request):
user = request.user
upload_form = UploadForm(request.POST or None, request.FILES or None)
if request.method == "POST":
if upload_form.is_valid():
my_model = upload_form.save(commit=False)
my_model.user = user
my_model.save()
models:
class FileStore(models.Model):
user = models.ForeignKey(User)
standard = models.FileField(upload_to="standard")
after_operation = models.FileField(upload_to="after_ocr",blank=True, null=True)
signal:
#receiver(post_save, sender=FileStore)
def my_handler(sender,instance, **kwargs):
if kwargs['created']:
text= image_to_string(Image.open(instance.standard))
...
instance.after_operation = File(text_file)
instance.save()
I want if file is .doc or .pdf save only in standard field and if file is .jpeg or .png I need run my signal function.
For instance, you can retrieve the uploaded file by accessing the request.FILES dictionary like this:
uploaded_file = request.FILES['file']
uploaded_file is now of type UploadedFile which means you can get info about the file like this:
# name of the file, ie: my_file.txt
filename = uploaded_file.name
# file extension (get the las 4 chars)
file_ext = filename[-4:]
# handle file extension
if file_ext == '.jpg':
# do something for jpegs
if file_ext == '.doc':
# do something for docs
So now, for saving it you may try this, I haven't prove it yet:
# f is the UploadedFile
model_file = File(f)
model_file.save('path/to/wherever.ext', f.readlines(), true)
I hope this helps! This may not work out of the box but I hope it bring some light to the problem. Try to look at the docs: django files and django uploaded files. This topic is very well documented.
Good luck!

Getting 'builtin_function_or_method object is not iterable' on file upload

I am unable to upload the file. I am getting
Type error builtin_function_or_method' object is not iterable
models.py
class seeker(models.Model):
user = models.OneToOneField(User)
birthday = models.DateField()
class Upload(models.Model):
user = models.ForeignKey(Seekers)
resume = models.FileField(upload_to ='resume', blank = True, null = True)
forms.py
class SeekersForm(forms.Form):
resume = forms.FileField(label = 'Select a file',help_text = 'max.3 MB')
views.py
def List(request):
# Handle file upload
if request.method == 'POST':
form = SeekersForm(request.POST, request.FILES)
if form.is_valid():
#id = User.object.get(id)
newdoc = Seekers.objects.get(user_id)
newdoc.resume =Upload(resume = request.FILES['resume'])
newdoc.save()
#seekers_edit = Seekers.objects.get(id)
#seekers_edit.resume = Seekers(resume = request.FILES['resume'])
#seekers_edit.save()
#Redirect to the document list after POST
return HttpResponseRedirect('/profile/')
else:
form = SeekersForm() # A empty, unbound form
#Load documents for the list page
seekers = Seekers.objects.all()
#Render list page with the documents and the form
return render_to_response('list.html',{'seekers':seekers,'form':form},context_instance=RequestContext(request))
It's hard to say where your problem is, but I think the following line of code is the main problem:
newdoc.resume =Upload(resume = request.FILES['resume'])
You have to save a file in a FileField explicitly before you save the entire model instance. Also, if you have a ForeignKey field in one of your models and you want to assign it an instance of another model, please save that instance first before you do the assignment. Without knowing your Seekers model, all I can do is guessing what might help you. Something like the following might get you started:
your_file = request.FILES['resume']
upload_instance = Upload()
upload_instance.resume.save(name=your_file.name, content=your_file, save=False)
upload_instance.user = ... # Here goes an instance of your Seekers model
upload_instance.save() # Here you save the whole instance of your Upload model
Also, please note the following:
Your model Seekers should rather be named Seeker using the singular, not the plural. This should generally be like that with all your models.
Python functions should always start with a lowercase letter, i.e. list instead of List. However, this name is a bad choice here anyway, because a function called list is already present in Python's standard library.
Please take a closer look at Django's documentation. It's all in there what you need to know. I recommend you to read especially these sections:
https://docs.djangoproject.com/en/1.4/ref/models/fields/#filefield
https://docs.djangoproject.com/en/1.4/ref/files/file/
Problems in your code:
Your form definition duplicates information from your model — just use forms.ModelForm (with exclude so as not to display the user field)
As currently pasted, newdoc = Seekers.objects.get(user_id) will raise a TypeError ('foo' object is not iterable); .get() accepts keyword parameter filters, not anything else.
Accessing request.FILES['resume'] manually isn't necessary or recommended
So, in short, you're almost there; just let Django forms do more of the work for you:
# forms.py
class SeekerForm(forms.ModelForm)
class Meta:
model = Seeker
# views.py
def seeker_list(request):
# Opinions are divided as to whether it's ever appropriate to
# modify the database like this on a GET request, but it seems
# to make sense here
seeker = Seekers.objects.get_or_create(user=request.user)
if request.method == 'POST':
form = SeekerForm(request.POST, request.FILES, instance=seeker)
if form.is_valid():
form.save()
return HttpResponseRedirect('/profile/')
else:
form = SeekerForm(instance=seeker)
seekers = Seekers.objects.all()
#Render list page with the documents and the form
return render_to_response('list.html', {
'seekers':seekers,
'form':form
}, context_instance=RequestContext(request))
It's not clear what the significance (if any) of the commented-out sections of your code is — I've assumed you always want to modify the current user's Seeker, but if not then adapt as appropriate.

Cannot upload an image in django using ImageField

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.