How to save uploaded file to disk in Django? - invalid mode: wb+ - python

I would like to know how to save an uploaded file to disk via django.
This is the code
# ...
def spreadsheet_form(request, id = None):
if is_admin_user(request):
instance = get_object_or_404(Spreadsheet, id=id) if id is not None else None
form = SpreadsheetForm(request.POST or None, request.FILES or None, instance=instance)
if form.is_valid():
spreadsheet = form.save(commit=False)
spreadsheet.name = request.POST['name']
spreadsheet.spreadsheet_file = request.FILES['spreadsheet_file']
handle_uploaded_file(request.FILES['spreadsheet_file'])
spreadsheet.save()
return redirect('/spreadsheets/')
return render_to_response("pages/spreadsheet_form.html", {"form": form,"id":id},context_instance=RequestContext(request))
else:
return redirect('/', False)
# ...
def handle_uploaded_file(f):
with open('/tmp/name.txt', 'wb+') as destination:
for chunk in f.chunks():
destination.write(chunk)
Currently it returns the following error:
invalid mode: wb+
Request Method: POST
Request URL: http://0.0.0.0:8000/spreadsheet/new/
Django Version: 1.4.5
Exception Type: IOError
Exception Value:
invalid mode: wb+

If your model Spreadsheet has a FileField, the only thing you need to do to save the file to disk is to pass request.FILES to the form and to save the form:
class Spreadsheet(models.Model):
file = models.FileField(upload_to="directory/relative/to/MEDIA_ROOT/")
other_field = ...
etc.
class SpreadsheetForm(forms.ModelForm):
class Meta:
model = Spreadsheet
fields = ['file', 'other_field', 'etc.']
def spreadsheet_form(request, id=None);
if is_admin_user(request):
instance = get_object_or_404(Spreadsheet, id=id) if id is not None else None
form = SpreadsheetForm(request.POST or None, request.FILES or None, instance=instance)
if form.is_valid():
spreadsheet = form.save()
return redirect('/spreadsheets/')
return render_to_response("pages/spreadsheet_form.html", {"form": form,"id":id},context_instance=RequestContext(request))
else:
return redirect('/', False)

Related

Storing data from csv file into model in django?

I am submitting csv file from form using POST method and want to save its content into model
forms.py
class SaveCsvForm(forms.Form):
upload_file = forms.FileField(label="Uplaod CSV File", help_text="Uploa file in CSV format")
Views.py
def save_csv(request):
if request.method == 'POST':
form = SaveCsvForm(request.POST, request.FILES)
if form.is_valid():
print("All ok I am check One")
# instance = CsvStorage(file_field=request.FILES['file'])
file = request.FILES['upload_file'].read()
print(file)
csv_to_db(file)
ack = {
'status': 'Success',
'message': 'Data is successfuly submited into database'
}
return JsonResponse(ack)
else:
ack = {
'status': 'Error',
'message': 'Server Returned '+form.errors.as_json(),
}
return JsonResponse(ack)
else:
form = SaveCsvForm()
return render(request, 'upload_csv.html', {'form': form})
file handler method for storing data in Model
def csv_to_db(filename):
with open(filename, 'r') as file:
''' reading csv file in dictionary format '''
reader = csv.DictReader(file)
for row in reader:
instance = CsvStorage(username=row['username'],
first_name=row['user'],
city=row['city'],
mobile=row['mobile']
)
instance.save()
if instance:
return({'status': 'successfuly'})
else:
return({'status': 'error'})
Note:
1.The main problem is while reading the file
2.I don't want to store file in models fileField
I ended up using FileSystemStorage class in Django as described in docs.

Two forms one view: model variable loses value

Here's my code
#login_required
def upload(request):
form_type = ''
transcript = Transcript()
transcript.file_path = ''
if request.method == 'POST':
if 'file_form' in request.POST:
file_form = FileForm(request.POST, request.FILES)
if file_form.is_valid():
path = handle_uploaded_file(request.FILES['file'], request.user)
transcript.file_path = path
transcript.user = request.user
export_form = InfoForm()
form_type = 'info_form'
elif 'info_form' in request.POST:
if transcript.file_path:
info_form = InfoForm(request.POST)
if info_form.is_valid():
transcript.user = request.user
transcript.title = info_form.cleaned_data.get('title')
transcript.instructions = info_form.cleaned_data.get('instructions')
transcript.save()
return HttpResponseRedirect('thanks')
else:
raise ValueError('Transcript object has no file path attribute')
else:
export_form = FileForm()
form_type = 'file_form'
return render(request, 'transcription/upload.html', {'form': export_form, 'form_type': form_type})
always, the file-form is called before the info-form, so the code in the if statement
if transcript.file_path:
#...
should always execute. But the ValueError always gets raised, meaning transcript.file_path is reset. How does this happen, and how can it be fixed?
file_form and info_form in POST are names of the different submit buttons, so I know which form I am dealing with.
def handle_uploaded_file(file, user):
id = randint(0, 10000)
user_dir = settings.MEDIA_ROOT + '/' + str(user.id).replace(".", "") + '/'
path = user_dir + file.name.replace(".mp3", str(id) + ".mp3")
if not os.path.exists(user_dir):
os.makedirs(user_dir)
with open(path, 'wb+') as destination:
for chunk in file.chunks():
destination.write(chunk)
file = File(destination)
info = {'path': path, 'file': file}
return path
So it was a rookie mistake.
I didn't know that during each post request the whole view gets called again.
So I just initialized my variables
form_type = ''
transcript = Transcript()
transcript.file_path = ''
outside the view and voila!

clean() method causes files to lose data using POST form

I have set up a form and view to upload multiple *.gpx files to my website at once. These files are validated using a clean() method on the form and then once validated passed to a function for processing.
When I upload some invalid files the clean() method catches them and informs the user as expected.
When I upload some valid files the processing function crashes with an error saying the files are empty.
If I comment out the clean() method then the valid files are uploaded fine.
What can be happening to the form during the clean() method than means the files are being blanked?
here is my form:
class UploadGpxForm(forms.Form):
gpx_file = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
here is my view:
class UploadGpxView(FormView):
form_class = UploadGpxForm
template_name = 'dashboard/upload.html' # Replace with your template.
success_url = reverse_lazy('dashboard:index') # Replace with your URL or reverse().
def post(self, request, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
files = request.FILES.getlist('gpx_file')
if form.is_valid():
for f in files:
SaveGPXtoPostGIS(f)
return self.form_valid(form)
else:
return self.form_invalid(form)
Here is my clean method for the UploadGpxForm:
def clean(self):
file_errors=[]
files = list(self.files.getlist('gpx_file'))
for f in list(files):
#check file has only one full stop in it.
if len(f.name.split('.')) != 2:
file_errors.append(ValidationError(
_('%(file_name)s has not been uploaded:'\
'File type is not supported')
, params = { 'file_name': f.name }
, code = 'file_type')
)
#check file doesn't breach the file size listed in settings
if f.content_type in settings.DASHBOARD_UPLOAD_FILE_TYPES:
if f._size > settings.DASHBOARD_UPLOAD_FILE_MAX_SIZE:
file_errors.append(ValidationError(
_('%(file_name)s has not been uploaded: File too big.'\
'Please keep filesize under %(setting_size)s.'\
'Current filesize %(file_size)s') ,
params = {
'file_name': f.name,
'setting_size': filesizeformat(
settings.DASHBOARD_UPLOAD_FILE_MAX_SIZE),
'file_size': filesizeformat(f._size)
},
code = 'file_size'
)
)
#check it is one of our allowed file types
else:
file_errors.append(ValidationError(
_('%(file_name)s has not been uploaded:'\
'File type is not supported')
, params = { 'file_name' : f.name }
, code = 'file_type'
)
)
#next check the file hasn't been uploaded before
#generate MD5
md5hash = md5()
for chunk in f.chunks():
md5hash.update(chunk)
file_hash = md5hash.hexdigest()
if gpxTrack.objects.filter(file_hash=file_hash).exists():
file_errors.append(ValidationError(
_('%(file_name)s has not been uploaded as a identical file'\
'has already been uploaded previously'),
params = { 'file_name' : f.name },
code = 'file_hash'))
#finally raise errors if there are any
if len(file_errors) > 0:
raise ValidationError(file_errors)
else:
return files
When you read the file content (for calculating md5 hash) you need to move the file object’s position to the beginning (0th byte) using file.seek:
md5hash = md5()
for chunk in f.chunks():
md5hash.update(chunk)
file_hash = md5hash.hexdigest()
f.seek(0) #<-- add this line

No hashing while trying to Hash using Python BCrypt

I have a view like:
def Registration(request):
RegForm = RegistrationForm(request.POST or None)
if request.method == 'POST':
if RegForm.is_valid():
clearUserName = RegForm.cleaned_data['userNm']
clearPass = RegForm.cleaned_data['userPass']
hashedpasswithsalt = bcrypt.hashpw(clearPass, bcrypt.gensalt(14))
RegForm.save()
try:
return HttpResponseRedirect('/Newuser/?userNm=' + clearUserName)
except:
raise ValidationError(('Invalid request'), code='300') ## [ TODO ]: add a custom error page here.
else:
RegForm = RegistrationForm()
return render(request, 'VA/reuse/register.html', {
'RegForm': RegForm
})
RegistrationForm
class RegistrationForm(ModelForm):
userPass = forms.CharField(widget=forms.PasswordInput, label='Password')
class Meta:
model = Client
fields = ['userNm','userPass']
Why is it storing in plaintext?
I'm trying to take the cleaned_data[] of userPass from a modelfrom and hash it prior to sending to the db.
Try bcrypt.hashpw(clearPass.encode("utf-8"), bcrypt.gensalt(14)).
This is because your clearPass is by default an Unicode object and that it can't be directly used in your hashing function, the encode("utf-8") converts it into a standard string and then it can be hashed.

How can I open a image from an ImageField before validating and saving a form?

I want to get the value of a CharField based on the value of an ImageField. My form and view are defined as:
#Form
class GpsImForm(forms.Form):
image = forms.ImageField(required=True)
gps_data = forms.CharField(required=True)
#View
def gpsim_gen_view(request):
if request.method == 'POST':
form = GpsImForm(request.POST, request.FILES)
if 'image' in request.FILES:
im = request.FILES['image']
i = Image.open(im)
... # functions to extract exif data from i
request.POST.update({ 'gps_data': ...}) # set gps_data based on exif data from i
if form.is_valid():
obj = form.save()
return ... #returns the gpsim
else:
form = GpsImForm()
return direct_to_template(request, 'gpsim_generate.html', {'form': form,})
The gps_data is updated, but, as soon as I use Image.open(), I get the following error message:
Upload a valid image. The file you uploaded was either not an image or a corrupted image.
If I comment the lines concerning i and modify the gps_data to whatever, the form (with the image) is saved without any error...
# i = Image.open(im)
# ...
# functions to extract exif data from i
request.POST.update({ 'gps_data': 'some text'}) # set gps_data to 'test'
first of all, make sure that your form has the enctype tag
<form enctype="multipart/form-data" ... >
Try to write the img (all the chunks) on disk:
import Image
from random import choice
from django.conf import settings
random_file_name = getattr(settings, 'FILE_UPLOAD_TEMP_DIR', '/tmp')
random_file_name += '/' + ''.join([choice('abcdefg') for i in range(12)]) + '.jpg'
destination = open(random_file_name, 'wb+')
for chunk in request.FILES['image'].chunks():
destination.write(chunk)
destination.close()
Then, you can open it from disk:
image = Image.open(random_file_name)
if image.mode != "RGB":
image = image.convert("RGB")
...
This URL may help you:
https://docs.djangoproject.com/en/dev/topics/http/file-uploads/
I finally found a cleaner solution:
I removed the "required=True" from my models and defined a clean() method which does the job in my form models:
#Form
class GpsImForm(forms.Form):
image = forms.ImageField(required=True)
gps_data = forms.CharField()
def clean(self):
super(forms.Form, self)).clean()
if not self.cleaned_data['gps_data']: # the user can provide the gps_data manually
if self.cleaned_data['image']: # if he provided no gps_data but an image
i = Image.open(self.cleaned_data['image'])
... # functions to extract exif data from i
else:
msg = _("You have to provide an image or a gps_data.")
self._errors['gps_data'] = self.error_class([msg])
return self.cleaned_data
#View
def gpsim_gen_view(request):
if request.method == 'POST':
form = GpsImForm(request.POST, request.FILES)
if form.is_valid():
obj = form.save()
return ... #returns the gpsim
else:
form = GpsImForm()
return direct_to_template(request, 'gpsim_generate.html', {'form': form,})

Categories

Resources