I need the Django Admin interface to accept administrator uploads of Excel files where the data in each Excel file is inserted into my database models. How can I make such an “Upload” button appear on a Django model admin page, where clicking the button asks the administrator to choose an .xls file, whose data then gets added to database once its upload is complete?
I have done this, but I just set up a simple view with a file upload (actually this makes more sense than adding it directly into a Django admin page, as one edit page = one model instance,and I assume that your excel contains multiple models).
in forms.py, a simple form with a file upload field
class ImportExcelForm(forms.Form):
file = forms.FileField(label= "Choose excel to upload")
in views.py, a view to process the upload
def test_flowcell(request):
c = RequestContext(request, {'other_context':'details here'})
if request.method == 'POST': # If the form has been submitted...
form = ImportExcelForm(request.POST, request.FILES) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
excel_parser= ExcelParser()
success, log = excel_parser.read_excel(request.FILES['file'] )
if success:
return redirect(reverse('admin:index') + "pages/flowcell_good/") ## redirects to aliquot page ordered by the most recent
else:
errors = '* Problem with flowcell * <br><br>log details below:<br>' + "<br>".join(log)
c['errors'] = mark_safe(errors)
else:
c['errors'] = form.errors
else:
form = ImportExcelForm() # An unbound form
c['form'] = form
return render_to_response('sequencing/file_upload.html')
and as suggested in the other post use xlrd to read the data in from the excel file. I have a separate file ExcelParser.py for this
import xlrd
class ExcelParser(object, excel_name):
#transaction.commit_on_success
def read_excel(self):
wb = xlrd.open_workbook(excel_name)
...
do your parsing in here.....
...
(May I add, that excel is a terrible, and error prone way to import data. I do a lot of it at my work, and am trying to convince management that there are far better solutions.)
I'm not sure about the Django side of things, but you can use xlrd to read and manipulate Excel files. There is a free PDF which explains this called Working with Excel files in Python
django-import-export could be helpful.
It creates two buttons "import" and "export" for admin objects and permits select many types of extensions, including xls. It also show the data do be imported and asks to be confirmed before execute the execution.
You just need to include it in INSTALLED_APPS and create an import-export resource of the class you want to upload and a subclass of ImportExportModelAdmin related to the resource class created before to show buttons in admin.
more info at:
http://django-import-export.readthedocs.org/en/latest/getting_started.html
https://github.com/bmihelac/django-import-export.
Related
what I needed is just an image was upload into uploads folder as example in web2py book.
Is this only possible with SQLForm ? or what wrong with my code.Here's my code.
model : db.py
db.define_table('image',
Field('title'),
Field('file', 'upload'),
format = '%(title)s')
in mysql image table was created title as varchar(70) file as mediumblob
controller
def index():
image_form = FORM(
INPUT(_name='image_title',_type='text'),
INPUT(_name='image_file',_class='upload',_type='file')
)
return locals()
view
{{extend "layout.html"}}
{{=form}}
I believe FORM can do everything SQLFORM can do except it requires a lot more effort. FORM simply creates a normal html form element. SQLFORM does that plus builds all the controls on the form and hooks up the Submit button.
I always try to use SQLFORM if I can.
Your code should show a form but it won't save anything to the database. That is because you are missing the crucial form.process commands. It is this command that does all the hard work of validating the form and adding or updating the record.
From the book and modified based on your code.
def index():
record = db.image(request.args(0)) # Tries to get an existing record where the id is specified in the first argument if the url.
image_form = SQLFORM(db.image, record) # Creates a form based on the 'image' table. If a record was found, it will show the record details
if image_form.process().accepted: # When the form is submitted (not when it is created) it will try and process it and add the record or save any changes to the record.
response.flash = 'form accepted'
elif image_form.errors:
response.flash = 'form has errors'
return dict(form=image_form)
A another problem is that you have called your form image_form in the controller but you are trying to display form in the view. My code above should work fine with your view - you can see that image_form is changed to form in the return command (form=image_form).
I have a basic view that retrieves some data, renders my page and sends some data to this page:
def myview(request)
one = values.objects.get(user=request.user).address
two = values.objects.get(user=request.user).number
return render(request, "main/mytemplate.html",
context={'address': one, 'numbers': two})
So the values retrieved by those two queries are shown on my page.
Now, on the same page, called mytemplate.html, i'm using another view, which is supposed to handle a form and some other operations:
def secondview(request):
if request.method == 'POST':
if 'button1' in request.POST:
form = MyForm(request.POST)
# check whether it's valid:
if form.is_valid():
profile = form.save(commit=False)
profile.user = request.user
profile.save()
return HttpResponseRedirect(request.path_info)
else:
form = MyForm()
return HttpResponse('it works!')
How can i use the data retrieved by those two queries in the second view? The queries are executed when the page is loaded by the first view. Then, in the same page the second view is used. I want to use the two variables one and two in the second view. Is there a way to do this in Django?
Why don't you make the same queries in the second view? Because i would like the second form to be as fast as possible in terms of reload, without having to do a DB query each time that view is used. Also, since i already retrieved those values when the page is opened, it would be a waste to do that again.
I don't know if this question is clear enough, but the core of it is: can i pass variables/data between two views in django?
You have few options:
Simplest way: include this data in request to the second view (as part of the form data, see an example below). You might even use a single view: if POST was send - store data else do request and show it on a page.
Use cache for that (see an example below) - But I'd recommend to use Django built-in package. Here is a basic example how to use it
Use Django Sessions (see an example below) - it is working option despite of that they have another purpose. When customer is loaded Django will load full session record, so you'll have all data in request.session variable. But that is bad practice: you can get a lot of data duplication and increased database memory consumption.
Use API (e.g. using DjangoRestFramework) together with usual Django app. So you'll just get data you need, and when you need. These API requests can also be cached so it is fast solution.
Yes, you can use session to pass data across views. A session works like a temporary server storage and keeps the needed data in a dictionary form.
For instance, add the following lines to myview:
request.session['one'] = one
request.session['two'] = two
Then, retrieve the data in secondview by referring to the session:
one = request.session['one']
two = request.session['two']
you can use cookies. but if you want more secure your request i suggest to you using redis and the python client for redis
file settings.py
redis = redis.Redis(host='localhost', port=6379, db=0)
file views.py
def view1(request):
redis.set("foo", "boo")
def view2(request):
boo = redis.get("foo")
Why not just saving the results of the two queries as hidden fields in the form rendered by the first template ?
<form ...>
<input type="hidden" id="address" name="address" value="{{address}}">
<input type="hidden" id="numbers" name="numbers" value="{{numbers}}">
...
Then, you can either add 'address' and 'numbers' form fields to MyForm
address = forms.CharField(widget=forms.HiddenInput(), required=False)
...
or just retrieve the values from request.POST
In my Django project i need to call from my function into my views.py an external page passing in POST format some data.
i do this:
in urls.py:
...
url(r'^gocard/(?P<lic_num>\w+)/$', go_ccredit),
...
in my views.py i create the function go_ccredit:
def go_ccredit(request, lic_num=None, **kwargs):
requests.post('https://www.example.com/form_test', data={'lid':lic_num,})
but i got an error because no HTTPResponse vas returned, and no page was open.
I need to open an external page because i need to populate some form field with my data (using POST) and some other have to be populated by user.
How can i open from my django function my external page passing data in POST ?
So many thanks in advance
I have a field where users upload an xlsx file In Django, however, im having trouble getting Django to return a simple text-based webpage from users uploading that xlsx file. Basically, I need Django to generate text from the cells of the xlsx file they uploaded. Im trying to use openpyxl to do this. How do I get Django to generate a new page with the results of the xlsx file after my script runs over it? Do I need to create a new template that redirects to it once the user submits the uploaded xlsx file? Here's an example.
# views.py
from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from .forms import UploadForm
import openpyxl
def index2(request):
if request.method != 'POST':
form = UploadForm()
else:
form = UploadForm(request.POST or None, request.FILES or None)
if form.is_valid():
form.save()
file = request.FILES['fileobj']
wb = openpyxl.load_workbook(file)
sheet = wb.get_sheet_by_name('Sheet1')
# script that runs overs the sheet here...
return HttpResponseRedirect(reverse('webpage with results'))
context = {'form': form}
return render(request, 'upload/upload_page.html', context)
I suggest decompose the problem. Right now you're trying to solve several things at once:
Upload the file
Save the file
Parse the file
Render a view of the file
I'd put 1) and 2) to the side and work on the XSLX loading/viewing part independently. For example, you could hard-code the path of the file in the view and get it rock solid that way. It's just development after all. Once it's good, remove the hard-coded file and connect up the real upload/save logic.
Realistically, you'll want to create a model class that represents say UploadedExcelFile. When the file is uploaded, create an instance and save it (i.e. a row in the database). Then you write a view that loads that model instance, which in turn can load the Excel file.
You might also want to consider ingesting the file rather than just storing on disk, or using some kind of async approach (e.g. django-q). This depends on a few factors, like what kind of information needs to be extracted from the file, is it editable etc. If it were me, and not knowing the bounds of your system, I'd do something like this:
Upload file
Store file in a temp area
Create a model object (i.e. database row) to represent the file and say the state is "processing".
Fire up a django-q job to ingest the file, giving it the filename
Return a view to this model.
The async job loads the file, parses the relevant aspects to json, stores the data in the model object (i.e. in the database), marks the model state as "ready".
The user can reload the page to see the data (or use websockets etc to tell it to reload).
I'm using Django to host a web application, and I would like to obtain a CSV file from the user, and process this information (using Python). I am currently using this line of code in the HTML to obtain the CSV file:
<input type="file" accept="text/csv" id="mycsv">
Where in the Django project should I obtain the information from the CSV file, and how would I go about doing this? (I know the question is broad and doesn't give context for my specific project, but I figure that once I know how to access the data in the CSV I can figure the rest out).
Step 1: upload the file
# forms.py
from django import forms
class UploadFileForm(forms.Form):
file = forms.FileField()
Step 2: parse data and update database
# views.py
import csv
from .models import YourModel
def myview(request):
if request.method == "POST":
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
reader = csv.reader(form.cleaned_data['file'])
for row in reader:
try:
some_instance = YourModel.objects.get_or_create(row[...])
...
Files uploaded by the user will go to the media folder that you have defined in your settings.py file.
You should be able to access user uploaded files in the media directory from your python code with something like this:
file_ = open(os.path.join(settings.MEDIA_ROOT, 'name_of_file'))
More info on MEDIA_ROOT and MEDIA_URL can be found here.