I have a model that has an ImageField. How can I manually assign an imagefile to it? I want it to treat it like any other uploaded file...
See the django docs for django.core.files.File
Where fd is an open file object:
model_instance.image_field.save('filename.jpeg', fd.read(), True)
Related
I am using Backblaze B2 and b2sdk.v2 in Flask to upload files.
This is code I tried, using the upload method:
# I am not showing authorization code...
def upload_file(file):
bucket = b2_api.get_bucket_by_name(bucket_name)
file = request.files['file']
bucket.upload(
upload_source=file,
file_name=file.filename,
)
This shows an error like this
AttributeError: 'SpooledTemporaryFile' object has no attribute 'get_content_length'
I think it's because I am using a FileStorage instance for the upload_source parameter.
I want to know whether I am using the API correctly or, if not, how should I use this?
Thanks
You're correct - you can't use a Flask FileStorage instance as a B2 SDK UploadSource. What you need to do is to use the upload_bytes method with the file's content:
def upload_file(file):
bucket = b2_api.get_bucket_by_name(bucket_name)
file = request.files['file']
bucket.upload_bytes(
data_bytes=file.read(),
file_name=file.filename,
...other parameters...
)
Note that this reads the entire file into memory. The upload_bytes method may need to restart the upload if something goes wrong (with the network, usually), so the file can't really be streamed straight through into B2.
If you anticipate that your files will not fit into memory, you should look at using create_file_stream to upload the file in chunks.
This is my model.
class Product(models.Model)
id = models.AutoField(max_length=10, primary_key=True)
name = models.CharField(max_length=60)
summary = models.TextField(max_length=200)
image = models.FileField(upload_to='product_images', blank=True)
I know how to import data from csv in django model. But I also have image field here.
Can I upload files to models from the method of adding data to models from csv? How?
I am using this method for importing them: http://mitchfournier.com/2011/10/11/how-to-import-a-csv-or-tsv-file-into-a-django-model/
I have images stored in a folder in my system.
FileField is just a reference to a file. It does not put a file into the database as is sometimes mistakenly believed.
Assuming that you have already got the code written for reading through the CSV and fetching the location of the file. Then all you need to do is to follow the example given in FileField.save()
This method takes a filename and file contents and passes them to the
storage class for the field, then associates the stored file with the
model field. If you want to manually associate file data with
FileField instances on your model, the save() method is used to
persist that file data.
Takes two required arguments: name which is the name of the file, and
content which is an object containing the file’s contents.
Something like this:
p = Product()
p.image.save('name from csv',open('path from csv'))
I solved it by saving the name of the image in the csv and just uploading the name in the field like this:
...
product.image = "product_images" + namefromcsv
then I uploaded all the images in the media folder inside product_images .
And it worked very well.
I tried uploading the image with product.image.save() option with File class but it didn't work for me.
I have a file bound to a form in this manner:
(forms.py)
class UploadFileForm(forms.Form):
wbfile = forms.FileField(label='Upload workbook' , help_text='Please Ensure file is in .xlsx format')
Now I have can access this in a view function using request.FILES['wbfile']. But I want to send this file to a template and then to another view function. So I bound it to a form like this:
f = form.fields['wbfile']
Now I want to save this file in the disk, but how do I access this file, this is what I am trying:
f = form.fields['file'].value()
with open(/tmp/xyz) as destination:
contents = f.read()
destination.write(contents)
But this throws an error saying: 'FileField' object has no attribute 'value'.
This is what for.fields[wbfile] shows:
<django.forms.fields.FileField object at 0x7f91ff1c49d0>
Hence the file is definitely bound to the form.
Please help and forgive me if the doubt is too obvious, I am a beginner!
I think there is everythink you need in the Django documentation.
For FileField : https://docs.djangoproject.com/en/dev/ref/models/fields/#filefield
Try using YourFileField.storage and YourFileField.path to have access to the file.
Then with this doc : https://docs.djangoproject.com/en/dev/ref/files/storage/
You can use open to open your file in memory. I guess it can give a code like this :
storage, path = YourFileField.storage, YourFileField.path
File f = storage.open(path)
I don't really understand what you want to do next, but if you want to save the file somewhere else, I guess you can probably use :
f.save(path) #or something similar, haven't tested any code like this
I'm using the Google App Engine Blobstore to store a range of file types (PDF, XLS, etc) and am trying to find a mechanism by which the original filename of the uploaded file - as stored in blob_info - can be used to name the downloaded file i.e. so that the user sees 'some_file.pdf' in the save dialogue rather than 'very_long_db_key.pdf'.
I can't see anything in the docs that would allow this:
http://code.google.com/appengine/docs/python/blobstore/overview.html
I've seen hints in other posts that you could use the information in blob_info to set the content-disposition header. Is this the best approach to achieving the desired end?
There is an optional 'save_as' parameter in the send_blob function. By default this is set to False. Setting it to True will cause the file to be treated as an attachment (ie it will trigger a 'Save/Open' download dialog) and the user will see the proper filename.
Example:
class ServeHandler(blobstore_handlers.BlobstoreDownloadHandler):
def get(self, resource):
resource = str(urllib.unquote(resource))
blob_info = blobstore.BlobInfo.get(resource)
self.send_blob(blob_info,save_as=True)
It is also possible to overwrite the filename by passing in a string:
self.send_blob(blob_info,save_as='my_file.txt')
If you want some content (such as pdfs) to open rather than save you could use the content_type to determine the behavior:
blob_info = blobstore.BlobInfo.get(resource)
type = blob_info.content_type
if type == 'application/pdf':
self.response.headers['Content-Type'] = type
self.send_blob(blob_info,save_as=False)
else:
self.send_blob(blob_info,save_as=True)
For future reference, save_as and the BlobstoreDownloadHandler is documented here:
http://code.google.com/appengine/docs/python/tools/webapp/blobstorehandlers.html
It does seem like it should be a bit easier to find. Let's see if it can be improved.
Another option is to append the file name to the end of the download URL. For example:
/files/AMIfv95HJJY3F75v3lz2EeyvWIvGKxEcDagKtyDSgQSPWiMnE0C2iYTUxLZlFHs2XxnV_j1jdWmmKbSVwBj6lYT0-G_w5wENIdPKDULHqa8Q3E_uyeY1gFu02Iiw9xm523Rxk3LJnqHf9n8209t4sPEHhwVOKdDF2A/prezents-list.doc
If you use Jinja2 for templating, you can construct such an URL like this:
{{file.filename}}
then you should adapt your URL mapping accordingly to something like this:
('/files/([^/]+)/?.*', DownloadHandler)
If you have the blob key in the URL, you can ignore the file name in your server-side code.
The benefit of this approach is that content types like images or PDF open directly in the browser, which is convenient for quick viewing. Other content types will just be saved to disk.
Yes it is the best approach; just query the BlobInfo object using the given Blobstore key and use its content-type property.
I would like to store large dataset generated in Python in a Django model. My idea was to pickle the data to a string and upload it to FileField of my model. My django model is:
#models.py
from django.db import models
class Data(models.Model):
label = models.CharField(max_length=30)
file = models.FileField(upload_to="data")
In my Python program I would like to do the following:
import random, pickle
data_entry = Data(label="somedata")
somedata = [random.random() for i in range(10000)]
# Next line does NOT work
#data_entry.file.save(filename, pickle.dumps(somedata))
How should I modify the last line to store somedata in file preserving the paths defined with upload_to parameter?
Based on the answers to the questions I came up with the following solution:
from django.core.files.base import ContentFile
import pickle
content = pickle.dumps(somedata)
fid = ContentFile(content)
data_entry.file.save(filename, fid)
fid.close()
All of it is done on the server side and and users are NOT allowed to upload pickles. I tested it and it works all fine, but I am open to any suggestions.
In you database the file attribute is just a path to the file. So, since you are not doing an actual upload you need to store the file on the disk and then save the path in database.
f = open(filename, 'w')
pickle.dump(somedata, f)
f.close()
data_entry.file=filename
data_entry.save()
Might you not be better off storing your data in a text field? It's not a file upload, after all.
I've never done this, but based on reading a bit of the relevant code, I'd start by looking into creating an instance of django.core.files.base.ContentFile and assigning that as the value of the field.
NOTE: See other answers and comments below - old info and broken links removed (can't delete a once-accepted answer).
Marty Alchin has a section on this in chapter 3 of Pro Django, review here.