I'm writing a page to upload a .csv file and import its content into my models. My current view:
class ContentImport(LoginRequiredMixin, PermissionRequiredMixin,View):
permission_required = 'delivery.change_delivery'
def get(self, request, *args, **kwargs):
form = UploadFileForm()
return render(request, 'delivery/content_import.html', { 'form': form })
def import_contents(self, f):
reader = csv.reader(f)
for row in reader:
print row[0]
def post(self, request, *args, **kwargs):
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
self.import_contents(request.FILES['file'].read())
messages.add_message(self.request, messages.SUCCESS, "Contents deleted successfully.")
return redirect(reverse('delivery:delivery-detail', args=[self.kwargs['delivery_id']]))
else:
messages.add_message(self.request, messages.ERROR, "Select a file to upload.")
return redirect(reverse('delivery:delivery-content-import', args=[self.kwargs['delivery_id']]))
My question is about the import_contents method and the call for it self.import_contents(request.FILES['file'].read()). When I print row[0] I get the following error: list index out of range.
My idea with this view is to upload a file, not saving it in the server, read the .csv from the memory and create new records in my models. This read from .csv I got from other answers here in stackoverflow.
I think the problem is how I pass the file to the import_contents function or how I read from it. I just can't figure out. Can you help me? If you have a suggestion on how to do it in an easier way, or the right way, let me know.
Thanks for any help
This is your problem.
self.import_contents(request.FILES['file'].read())
csv.reader() expects a file like object, not its content.
This can definitely be construed as a related answer.
Related
I have code like this. It's working example of saving data specified in forms.py, and some data taken from current logged user.
#login_required
def save(request):
if request.method == 'POST':
form = ExcelForm(data=request.POST)
if form.is_valid():
name = request.user.first_name
lastname = request.user.last_name
date = datetime.datetime.now().date()
valid_form = form.save(commit=False)
valid_form.firstName = name
valid_form.lastName = lastname
valid_form.date = date
valid_form.save()
return redirect('account:panel')
else:
form = ExcelForm(data=request.POST)
return render(request, 'account/panel.html', {'form': form})
This form is saved to sqllite db. My main goal is to save this form as excel file. How can I deal with this problem ? How to pass data to the sheet and with clicking submit button in my html file saving to excel file and to database in the same time ? thanks for all answers in the future.
Rather than storing the data in excel, you can create a new view to export the data as excel format. You can try like this using django-import-export. Example of writing a view:
from django.http import HttpResponse
from .resources import PersonResource
def export(request):
person_resource = PersonResource()
dataset = person_resource.export()
response = HttpResponse(dataset.xls, content_type='application/vnd.ms-excel')
response['Content-Disposition'] = 'attachment; filename="persons.xls"'
return response
You can check this medium post as well for exporting data using view.
I'm running Django on a localhost (Later to run on a LAN) where the idea is I can go onto the webpage, click a button where you're prompted to select an excel file from your computer. Pandas will do work on said excel file and Django/Pandas will make excel file of this Pandas data frame as a download prompt.
I've got Django running and using the code below from the module 'Django-Excel' does the basics of what I want. Excel file in ---> excel file out, no saving the file to a database or anything just keeping it in the memory. However, I cannot find a way to shoehorn Pandas into it. The main problem I have is I'm unsure how to return an excel file using Pandas. I've been using '.to_excel()' in my offline python code, however, haven't found a way to use it in a localhost running Django. I'm sure I'm missing something really simple but I just can't get it.
Maybe if someone could show a simple example of say, uploading an excel, pandas will multiply a column of numbers in the excel by 2, new excel is outputted to read/save.
from django.shortcuts import render, redirect
from django.http import HttpResponseBadRequest, HttpResponse
from _compact import JsonResponse
from django import forms
import django_excel as excel
from polls.models import Question, Choice
class UploadFileForm(forms.Form):
file = forms.FileField()
# Create your views here.
def upload(request):
if request.method == "POST":
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
filehandle = request.FILES['file']
# do pandas here to filehandle/ put filehandle into a function
return excel.make_response(filehandle.get_sheet(), "csv",
file_name="download")
else:
form = UploadFileForm()
return render(
request,
'upload_form.html',
{
'form': form,
'title': 'Excel file upload and download example',
'header': ('Please choose any excel file ' +
'from your cloned repository:')
})
Thank you very much, sorry if this isn't clear It's my first time posting on this website, if you don't understand what I'm asking for I'll elaborate more.
I'll upload my answer for anyone looking at this in the future :-)
def uploads(request):
if request.method == "POST":
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
kappa = request.FILES['file']
# Do work on kappa/excel file here with Pandas
output = io.BytesIO()
writer = pd.ExcelWriter(output, engine='xlsxwriter')
kappa.to_excel(writer, index=False)
writer.save()
output.seek(0)
response = HttpResponse(output,
content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = 'attachment; filename=%s.xlsx' % 'Download'
return response
else:
form = UploadFileForm()
return render(request, 'upload_form.html', {'form': form})
I abandoned using 'Django-excel' and instead used 'BytesIO' from the io module. This has the bonus of not relying on a third-party module.
you're able to write a Pandas dataframe to io.BytesIO() and then use that in your HttpResponse.
I am trying to allow a user to edit their profile. In the post method I want to save the new data over the old data in the same row.
# Post method of class view in views.py
def post(self, request, username):
try:
user = User.objects.get(username=username)
except User.DoesNotExist:
raise Http404('The User "' + username + '" could not be found.')
if (not request.user.is_authenticated):
return HttpResponseForbidden()
elif (user.id is not request.user.id):
return HttpResponseForbidden()
form = self.form_class(request.POST)
if (form.is_valid()):
# creates a new user object, does not save to the database yet
profile = form.save(commit=False)
# clean (normalized) data
# ...
profile.save()
if (user.is_active):
return redirect('/profile/' + user.username)
return render(request, self.template_name, {'form': form, 'error_message': 'Oops, something went wrong'})
This code I believe is creating a new database row when the post method is called. How do I get it to update the existing row in a clean looking solution?
If you use Django's UpdateView then it takes care of a lot of these details with saving the ModelForm.. including saving the update, redirecting the user upon success, and redisplaying the form with errors shown if there's a problem.
I have a view :
class SomeView(FormView):
form_class = SomeForm
template_name = 'app/template.html'
def get(self, request, *args, **kwargs):
form = self.form_class
return render(request, self.template_name, {form:'form'})
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_Valid():
#do something here
return HttpResponseRedirect("Go somewhere from here after processing")
In the post I need to make an API call which takes data from this form. Instead of this though, I want to redirect user to another view, where he can view all the data from the form and say confirm
On submit of this confirm view I should actually make this API call.
How do I pass the form data to another view ? I can simply store the form data in a dict and pass it on from the URL, but that might expose some crucial data at the browser level.
Is there a safer way to do this ?
Thanks
Yes, there is a litle helper from django:
https://docs.djangoproject.com/en/1.5/ref/contrib/formtools/form-preview/
i try to upload a csv file into my web application and store it into mysql database but failed.Please can anyone help me?
my user.py script:
def import_contact(request):
if request.method == 'POST':
form = UploadContactForm(request.POST, request.FILES)
if form.is_valid():
csvfile = request.FILES['file']
print csvfile
csvfile.read()
testReader = csv.reader(csvfile,delimiter=' ', quotechar='|')
for row in testReader:
print "|".join(row)
return HttpResponseRedirect('/admin')
else:
form = UploadContactForm()
vars = RequestContext(request, { 'form': form })
return render_to_response('admin/import_contact.html', vars)
my forms.py script:
class UploadContactForm(forms.Form):
file = forms.FileField(label='File:', error_messages = {'required': 'File required'})
Since you haven't provided the code for the getcsv function, I'll have to use my crystal ball here a bit.
One reason why the print in the for row in testReader: loop isn't working is that getcsv may already processes the file. Use the seek method to reset the objects position in the file to zero again. That way the for loop will process it properly.
Another reason why there's nothing stored in the database might be that in the code you've supplied there doesn't seem to be a reference to a model. So how should Django know what it should store and where?