Passing uploaded file to template -- Django - python

I was following the instructions from the top comment of this post: Need a minimal Django file upload example and this is my views.py. I'm not interested in creating a list of files, so I removed that.
def reikna(request):
if request.method == 'POST':
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
new_doc = Document(docfile = request.FILES['docfile'])
# Marks the file as /options/ file
new_doc.save()
# Redirect to the document list after POST
#return HttpResponseRedirect(reverse('notendur.views.options'))
else:
form = DocumentForm() # An empty, unbound form
return render('file_view2.html', {'new_doc': new_doc})
However, when I do this, I get
UnboundLocalError: local variable 'new_doc' referenced before assignment
Does this have something to do with the scope of new_doc? How should I do this?
EDIT __ My model
class Document(models.Model):
docfile = models.FileField(upload_to=_upload_path)
def get_upload_path(self,filename):
return "uploads/"+str(self.user.id) + '/' + str(date.today()) + '/' + filename

Related

Check if a file exist in Django

I have created a newclaim.html and editclaims.html. newclaims.html allows me to upload a file while editclaims.html allows me to retrieve the file.
Currently, I am able to retrieve the uploaded file but I want to do an if-else. I want to do an if-else that will delete the old file if a new file is uploaded
This is my views.py
**# Submit a new Claim**
def newclaim(request):
context = initialize_context(request)
user = context['user']
if request.method == 'POST':
receipt = request.FILES['receipt_field']
ins = SaveClaimForm(receipt=receipt)
ins.save()
print("The Data has been written")
return render(request, 'Login/newclaim.html/', {'user':user})
# Edit a claim
def editclaims(request,id):
context = initialize_context(request)
user = context['user']
# get original object
claims = SaveClaimForm.objects.get(id=id)
if request.method == 'POST':
# update original object
claims.receipt = request.FILES.get('receipt')
# save it with original `ID`
claims.save()
return render(request, "Login/editclaims.html", {'claims':claims, 'user':user})
You can check if the old file exist in your file path and delete it. May refer to the code below and modify as per your need :
def editclaims(request,id):
context = initialize_context(request)
user = context['user']
# get original object
claims = SaveClaimForm.objects.get(id=id)
if request.method == 'POST':
# get the old file name:
old_file = claims.receipt
# update original object
claims.receipt = request.FILES.get('receipt')
# save it with original `ID`
claims.save()
#Delete the old file from os if it exist
#Do not forget to import os
#FILE_PATH = path to your file directory
if os.path.isfile(FILE_PATH+old_file):
os.remove(FILE_PATH+old_file)
return render(request, "Login/editclaims.html", {'claims':claims, 'user':user})

Read a csv file and fill in database with it's data in django application

in my Django application, i created a form which permit user to upload csv file.
What i want is when user upload the csv file, the contained data is read and database is filled in with them.
It works but not correctly. data are saved as tuples.
Here's my code
forms.py
class SupplierCSVForm(forms.ModelForm):
class Meta:
model = SuplierCsv
fields = '__all__'
exclude = ('slug',)
views.py
#login_required
def l_supplier(request):
suppliers_list = Supplier.objects.all()
paginator = Paginator(suppliers_list, 3, 2)
page = request.GET.get('page')
suppliers = paginator.get_page(page)
# Supplier csv form
if request.method == 'POST':
form = SupplierCSVForm(request.POST, request.FILES)
if form.is_valid():
uploaded_file = request.FILES['csvfile']
with open('f.csv', 'wb') as destination:
for chunk in uploaded_file.chunks():
destination.write(chunk)
destination.close()
#csvfile = io.TextIOWrapper(open('f.csv', 'rb'))
with open('f.csv', 'r') as the_source:
source_reader = csv.reader(sthe_source)
next(source_reader)
for Name, Email, Contact, City, Website, Activity, Cc, slug in source_reader:
new_supplier = Supplier()
new_supplier.name=Name,
new_supplier.email=Email,
new_supplier.contact=Contact,
new_supplier.city=City,
new_supplier.website=Website,
new_supplier.activity=Activity,
new_supplier.cc=Cc,
new_supplier.slug=slug,
new_supplier.save()
return redirect('good:l_good')
else:
form = SupplierCSVForm()
context = {
'suppliers': suppliers,
'form': form,
}
return render(request, 'supplier/l_supplier.html', context)
Remove the commas where you are assigning the new_supplier objects. Python converts your string objects into tuples if there are any trailing commas.
You have unnecessary commas at the end of your lines:
new_supplier.name=Name,
should be
new_supplier.name=Name
Python thinks that you are creating a tuple
i.e. x, == (x,)

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!

submitting two forms one after another

I am working on my first django webaite, I am trying to submit two forms one after the other.
Here is the views.py :
def home(request):
import json
if request.method == 'POST':
form = MajorForm(request.POST)
if form.is_valid():
url = 'http://www.mysite.com:8082'
dataout = {'my':'data'}
headers = {'content-type':'application/json'}
r = requests.post(url,data=json.dumps(dataout),headers=headers)
return collector(request)
else:
return HttpResponse("thnx")
else:
form = MajorForm()
return render(request,'index.html',{'form':form})
def collector(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
return HttpResponse("thanx")
else:
return HttpResponse("not valid")
else:
form = ContactForm();
return render(request,'collector.html',{'form':form})
So the first view calls the second view. The first form works fine, and the second form is also displayed fine, but submitting the second form does not work at all ( I was never able to get to form.is_valid path). Maybe this entire approach of calling one view from another is not correct? What would be the right one?
Please indent your code correctly. Also you are missing an else in the collector function when the request.method is not POST.

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