Django and xlrd, reading from memory - django

My plan is to let a user to upload an excel file, once uploaded I will be displaying editable form which contains the content of the uploaded excel, once user confirms the input is correct, he/she hits the save button and these items are saved at some model.
For this, I have written this view and form:
form:
IMPORT_FILE_TYPES = ['.xls', ]
class XlsInputForm(forms.Form):
input_excel = forms.FileField(required= True, label= u"Upload the Excel file to import to the system.")
def clean_input_excel(self):
input_excel = self.cleaned_data['input_excel']
extension = os.path.splitext( input_excel.name )[1]
if not (extension in IMPORT_FILE_TYPES):
raise forms.ValidationError( u'%s is not a valid excel file. Please make sure your input file is an excel file (Excel 2007 is NOT supported.' % extension )
else:
return input_excel
view:
def import_excel_view(request):
if request.method == 'POST':
form = XlsInputForm(request.POST, request.FILES)
if form.is_valid():
input_excel = request.FILES['input_excel']
# I need to open this input_excel with input_excel.open_workbook()
return render_to_response('import_excel.html', {'rows': rows})
else:
form = XlsInputForm()
return render_to_response('import_excel.html', {'form': form})
As you can see at the # I need to open this input_excel with input_excel.open_workbook() I need to read from memory but open_workbook reads from a file, without saving this input to somewhere, how can I read it ?

if form.is_valid():
input_excel = request.FILES['input_excel']
book = xlrd.open_workbook(file_contents=input_excel.read())
# your work with workbook 'book'
return render_to_response('import_excel.html', {'rows': rows})
When file_contents optional keyword is provided, filename keyword will not be used.
Happy Coding.

Related

Save content of zip file in django

Good Day,
I would like to save the content of the zip file. My code works, but they save only the filename and not the content or actual files neither in the database nor the project.
I need to save in the database the content of each file. Can someone please help me to fix my error? My code looks like this:
uploaded_file, = request.FILES.getlist('document[]')
with zipfile.ZipFile(uploaded_file.file, mode="r") as archive:
for zippedFileName in archive.namelist():
newZipFile = UploadedFile(document= zippedFileName)
newZipFile.user= request.user
files = newZipFile.save()
success=True
return render(request, 'uploader/index.html', {'files': [uploaded_file]})
You have to save your zipfile on your filesystemstorage : https://docs.djangoproject.com/fr/4.1/ref/files/storage/
Or you can use a BinaryField in your models and try to save your zipfile as encoded binary : https://docs.djangoproject.com/fr/4.1/ref/models/fields/#binaryfield
THe better way is clearly the usage of a FS i think
For people looking on how to save the content of a zip file, this solution works for me
IMAGE_FILE_TYPES = ['png', 'jpg', 'jpeg']
def PostCreate(request):
form = PostForm()
if request.method == 'POST':
form = PostForm(request.POST, request.FILES)
if form.is_valid():
user_pr = form.save(commit=False)
user_pr.album_image = request.FILES['album_image']
with zipfile.ZipFile(user_pr.album_image, mode="r") as archive:
for fileName in archive.namelist():
file_type = fileName.split('.')[-1]
file_type = file_type.lower()
if file_type not in IMAGE_FILE_TYPES:
print("ERROR!!!")
else:
file= archive.extract(fileName, settings.MEDIA_ROOT + 'UnzippedFiles')
rbe = Post.objects.create(album_image=file)
rbe.save()
print("SUCESS!!!")
return render(request, 'photos/post.html', {'user_pr': user_pr})
context = {"form": form,}
return render(request, 'photos/post_form.html', context)

Django validate FileField with clean()

I have a Form that includes a FileField and a CharField. Both work as expected.
Neither field is required by itself, but one of them has to be given. So I want to add a validation that fails if both are empty.
in forms.py:
class MyForm(forms.Form):
mytext = forms.CharField(
label = "Enter text",
required=False
)
myfile = forms.FileField(
label = "Or upload file",
required=False
)
def clean(self):
super(MyForm, self).clean()
mytext_value = self.cleaned_data.get("mytext")
myfile_value = self.cleaned_data.get("myfile") # this remains empty, even after selecting a file! :-(
if not mytext_value and not myfile_value:
self.add_error("mytext", "Either text or file must be given!")
return self.cleaned_data
This validation fails even if a file has been uploaded! (It does not fail if the text field has been used.)
If I disable the validation, the form works fine within the app. In views.py, I can get the uploaded file from the request (myfile_value = request.FILES.get("myfile")) and work with it.
But how do I get the content of the file during the clean() call, where I do not have a request, yet?
self.files gives me an empty MultiValueDict, self.data doesn't contain the key myfile at all, and in self.cleaned_data, myfile is None.
How can I check during form validation whether a FileField has been filled?
The problem was not the form, but the associated view:
Wrong forms.py:
if request.method == "POST":
form = MyForm(request.POST)
if form.is_valid():
mytext = request.POST.get("mytext")
myfile = request.FILES.get("myfile")
I didn't pass request.FILES to the form, so no wonder the validation didn't find it. While below this point, I retrieved the file directly from the request and was fine.
Right forms.py:
if request.method == "POST":
form = MyForm(request.POST, request.FILES)
if form.is_valid():
mytext = form.cleaned_data.get("mytext")
myfile = form.cleaned_data.get("myfile")

Django: Adding an if statement to check if file as been uploaded in a contact form

I have a website contact form that involves attaching several optional documents. Once the form has been filled out, an email is sent to an employee which includes form inputs along with these documents as email attachments. I am looking to add an if statement before the msg.attach_file command in my views.py file that prevents attaching the file if a document was never uploaded. Something along the lines of...
if upload_file_type2 blank = false
msg.attach_file('uploads/filetype2/')
I know that above line is incorrect, but I am unsure of how to write an if-statement that says the form entry was blank. Below are relevant files.
Models.py
upload_file_type1 = models.FileField(upload_to=file_path1, blank=True)
upload_file_type2 = models.FileField(upload_to=file_path2, blank=True)
Views.py
def quote_req(request):
submitted = False
if request.method == 'POST':
form = QuoteForm(request.POST, request.FILES)
upload_file_type1 = request.FILES['upload_file_type1']
upload_file_type2 = request.FILES['upload_file_type2']
if form.is_valid():
form.save()
# assert false
msg = EmailMessage('Contact Form', description, settings.EMAIL_HOST_USER, ['sample#mail.com'])
msg.attach_file('file_path1')
#THIS IS WHERE PROPOSED IF STATEMENT WOULD GO
msg.attach_file('file_path2')
msg.send()
return HttpResponseRedirect('/quote/?submitted=True')
else:
form = QuoteForm()
if 'submitted' in request.GET:
submitted = True
You would generally do something like this:
upload_file_type2 = request.FILES.get('upload_file_type2', None)
if upload_file_type2 is not None:
# File is present, can attach
# . . .
That's probably the best method. Alternatively, can also do something like the following
if 'upload_file_type2' in request.FILES:
# Here it is already not empty, and you can attach
upload_file_type2 = request.FILES['upload_file_type2']
# . . .

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!

Django: How to prepopulate file upload path with current file path?

I have a modelform that my views generate an HTML form for editing content. Currently, it's able to pull in the current stored text content, like this:
#login_required
def edit_person(request, s_id, p_id):
p = get_object_or_404(Person, id=p_id)
if request.method == 'POST':
form = PersonForm(request.POST, request.FILES)
if form.is_valid():
p.name = request.POST['name']
p.title = request.POST['title']
handle_uploaded_file(request.FILES['photo'], request.FILES['photo'].name, 'media/images/people/')
p.photo = request.FILES['photo']
p.order = request.POST['order']
p.save()
return HttpResponseRedirect('/section/'+s_id+'/')
else:
return HttpResponse("error")
else:
form = PersonForm({ 'name': p.name, 'title': p.title, 'photo': p.photo, 'order': p.order })
return render_to_response('auth/edit-form.html', { 'form': form }, context_instance=RequestContext(request))
return HttpResponseRedirect('/section/'+s_id+'/')
However, the photo file path is blank. I don't want the user to have to upload a new file every time they edit something if they don't want to change the image. How do I get the file upload field to appear pre-populated and not overwrite itself if they don't change it? Thanks.
Believe it or not, it can be done! However, it requires the use of a custom django app called django-file-resubmit
Note that app as given only works for the widgets in admin and requires sorl-thumbnail.
You may prefer to use my fork:
https://github.com/JordanReiter/django-file-resubmit
It's a general-purpose version for use everywhere a ModelForm is used that doesn't have any other prerequisites.
It's pretty cool in that it automagically stores the file on submission (even if there is a validation error) and retrieves it from the cache when the widget is rendered in the form.
This is literally all you have to do to implement it:
import file_resubmit.widgets
class PersonForm:
""" existing code here """
photo = forms.ImageField(required=False, widget=file_resubmit.widgets.ResubmitImageWidget())