I'm developing my app on Windows with GAE, but the below error message was shown.
C:\Python27\Lib\site-packages
Perhaps your account does not have write access to this directory? You can
change the cache directory by setting the PYTHON_EGG_CACHE environment
variable to point to an accessible directory.
So I checked some post in this site and I found some articles but I could not understand it. My understanding is that I need to create cache directory with write access in home directory, but I did not understand where "home directory" is.
Also in other post, I found the answer saying This approach solved my issue. I did uninstall pyyaml using pip and then installed it with easy_install -z pyyaml
Which approach is correct?
import webapp2
import os
import jinja2
import cloudstorage
import mimetypes
from PIL import Image
from google.appengine.ext import ndb
from google.appengine.ext import blobstore
from google.appengine.api import users
from google.appengine.api import app_identity
from google.appengine.api import images
from models import Note
from models import CheckListItem
from models import NoteFile
jinja_env = jinja2.Environment(loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))
images_formats = {
'0':'image/png',
'1':'image/jpeg',
'2':'image/webp',
'-1':'image/bmp',
'-2':'image/gif',
'-3':'image/ico',
'-4':'image/tiff',
}
class MainHandler(webapp2.RequestHandler):
def get(self):
user = users.get_current_user()
if user is not None:
logout_url = users.create_logout_url(self.request.uri)
template_context = {
'user': user.nickname(),
'logout_url' : logout_url,
}
template = jinja_env.get_template('main.html')
self.response.out.write(template.render(template_context))
else:
login_url = users.create_login_url(self.request.uri)
self.redirect(login_url)
def post(self):
user = users.get_current_user()
if user is None:
self.error(401)
bucket_name = app_identity.get_default_gcs_bucket_name()
uploaded_file = self.request.POST.get('uploaded_file')
file_name = getattr(uploaded_file,'filename',None)
file_content = getattr(uploaded_file,'file',None)
real_path = ''
if file_name and file_content:
content_t = mimetypes.guess_type(file_name)[0]
real_path = '/' + bucket_name + '/' + user.user_id() + "/" + file_name
with cloudstorage.open(real_path,'w',content_type=content_t,options={'x-goog-acl':'public-read'}) as f:
f.write(file_content.read())
self._create_note(user, file_name, real_path)
logout_url = users.create_logout_url(self.request.uri)
template_context = {
'user':user.nickname(),
'logout_url': logout_url,
}
self.response.out.write(self._render_template('main.html',template_context))
def _render_template(self,template_name,context=None):
if context is None:
context = {}
user = users.get_current_user()
ancestor_key = ndb.Key("User",user.nickname())
qry = Note.owner_query(ancestor_key)
context['notes'] = qry.fetch()
template = jinja_env.get_template(template_name)
return template.render(context)
#ndb.transactional
def _create_note(self,user,file_name,file_path):
note = Note(parent=ndb.Key("User", user.nickname()), title=self.request.get('title'), content=self.request.get('content'))
note.put()
item_titles = self.request.get('checklist_items').split(',')
for item_title in item_titles:
item = CheckListItem(parent=note.key, title=item_title)
item.put()
note.checklist_items.append(item.key)
if file_name and file_path:
url, thumbnail_url = self._get_urls_for(file_name)
f = NoteFile(parent=note.key, name=file_name, url=url,thumbnail_url=thumbnail_url,full_path=file_path)
f.put()
note.files.append(f.key)
note.put()
def _get_urls_for(self,file_name):
user = users.get_current_user()
if user is None:
return
bucket_name = app_identity.get_default_gcs_bucket_name()
path = '/' + bucket_name + '/' + user.user_id() + '/' + file_name
real_path = '/gs' + path
key = blobstore.create_gs_key(real_path)
try:
url = images.get_serving_url(key, size=0)
thumbnail_url = images.get_serving_url(key,size=150,crop=True)
except images.TransformationError,images.NotImageError:
url = "http://storage.googleapis.com{}".format(path)
thumbnail_url = None
return url,thumbnail_url
class MediaHandler(webapp2.RequestHandler):
def get(self,file_name):
user = users.get_current_user()
bucket_name = app_identity.get_default_gcs_bucket_name()
content_t = mimetypes.guess_type(file_name)[0]
real_path = '/' + bucket_name + '/' + user.user_id() + '/' + file_name
try:
with cloudstorage.open(real_path,'r')as f:
self.response.headers.add_header('Content-Type',content_t)
self.response.out.write(f.read())
except cloudstorage.errors.NotFoundError:
self.abort(404)
class ShrinkHandler(webapp2.RequestHandler):
def _shrink_note(self,note):
for file_key in note.files:
file = file_key.get() # this is the same as "file.get().url" in html file. we add the comment.
try:
with cloudstorage.open(file.full_path) as f:
image = images.Image(f.read())
image.resize(640)
new_image_data = image.execute_transforms()
content_t = images_format.get(str(image.format))
with cloudstorage.open(file.full_path,'w',content_type=content_t) as f:
f.write(new_image_data)
except images.NotImageError:
pass
def get(self):
user = users.get_current_user()
if user is None:
login_url = users.create_login_url(self.request.url)
return self.redirect(login_url)
ancestor_key = ndb.Key("User",user.nickname())
notes = Note.owner_query(ancestor_key).fetch()
for note in notes:
self._shrink_note(note)
self.response.write('Done.')
app = webapp2.WSGIApplication([
(r'/', MainHandler),
(r'/media/(?P<file_name>[\w.]{0,256})',MediaHandler),
(r'/shrink',ShrinkHandler)
], debug=True)
It looks like you're developing a standard env GAE app but you're attempting to install third party libraries in (and use them from) your local system's site packages. This won't work.
You need to install the third party libraries in your app's library directory (i.e. using -t <your_lib_dir> option for pip install, for which you shouldn't need special permissions. See also:
Using third-party libraries.
No module named warnings when starting GAE inside virtualenv locally
Related
I've created an angular component (product) on which a user is able to change an image (product's image).
html:
<img [attr.id]="_product.id" [attr.src]="_product.thumbnail_url"/>
When the image is chosen by the user from a custom file picker component on a modal form. The following method is called to reload the image in the parent product component.
The imageBinary here is a base64 blob binary image returned from a python FLASK REST API endpoint which is connected to a mysql database.
reloadProductImage(new_image_id):void{
let newUrl:SafeUrl;
let urlStr:string;
this.productservice.getImage(new_image_id).subscribe((filedata) =>{
let imageBinary = filedata.thumbnail;
urlStr = 'data:image/jpeg;base64,' + imageBinary + '?'+Date.now();
newUrl = this.domSanitizer.bypassSecurityTrustUrl(urlStr);
this.form.patchValue({image_id: new_image_id});
this._product.thumbnail_url = newUrl;
this._product.image_id = new_image_id;
I've found many examples how to force the browser to a reload on a regular src url by appending a timestamp to the url. However, these examples do not seem to apply to a blob stored in a saferurl.
inspect image element
<img _ngcontent-snv-c187="" id="146914e3-6e0a-409f-8046-ff04580f6242" src="data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgA+++very+long+blob+++vBzu3ZFwwAAAABJRU5ErkJggg==?1619156455998">
Console Error message
Failed to load resource: net::ERR_INVALID_URL
Failed attempts
I've tried:
newUrl = 'data:image/jpeg;base64,' + imageBinary + '?'+ Date.now();
and
newUrl = 'data:image/jpeg;base64,' + imageBinary + '?datetime='+ Date.now();
Background info
For illustration purposes, I'll post my Angular and Python code here (methods in a Flask SQLAlchemy DB Model) which post an image file to a Flask REST API, generate the thumbnail from the base64 image and return it to Angular. Note: the get function is called in a GET request. The Create function is called in a POST request.
Angular FileUpload component:
import { HttpClient } from '#angular/common/http';
import { Component, OnInit, Output, EventEmitter } from '#angular/core';
import {NotificationService} from '../..//notification/notification.service';
#Component({
selector: 'fileupload-form',
template: `
<p>
Productfoto toevoegen
</p>
<input type="file" (change)="onFileSelected($event)">
<button type="button" (click)="onUpload()">Upload</button>
`,
styles: [
]
})
export class FileuploadComponent implements OnInit {
selectedFile: File = null;
#Output()
fileSubmitted = new EventEmitter();
constructor(private http: HttpClient,
private notificationService: NotificationService,
) { }
onFileSelected(event){
this.selectedFile = <File>event.target.files[0];
}
onUpload(){
const fd = new FormData();
fd.append('inputFile', this.selectedFile , this.selectedFile.name);
this.http.post(['/offerte/api/files','upload'].join('/'),fd)
.subscribe(res => {
console.log(res);
this.notificationService.success(`Bestand ${this.selectedFile.name} is opgeslagen.`);
this.fileSubmitted.emit(res);
})
}
ngOnInit(): void {
}
}
Python Flask Endpoints:
Imports
import logging
from io import BytesIO
from flask import request, send_file
from flask_restx import Resource
from api.serializers import fileobject, page_of_files
from api.parsers import pagination_arguments
from api.restplus import api
from database.models import File
from flask_jwt_extended import jwt_required, get_jwt_identity
logger = logging.getLogger()
ns_files = api.namespace('files', description='Operations related to file management')
POST
#ns_files.route('/upload')
class Upload(Resource):
#api.doc(security='jwt')
#jwt_required
def post(self):
'''Upload a new file, returns id of new file'''
inputFile = request.files['inputFile']
logger.info('create new file %s', request.json)
current_user = get_jwt_identity()
return File.create(inputFile, current_user)
GET
#ns_files.route('/<string:file_id>')
#api.response(404, 'file not found')
class Details(Resource):
#api.marshal_with(fileobject)
def get(self, file_id):
'''Download a new file from the db (binary storage)'''
logger.info('loading file %s')
current_user = get_jwt_identity()
returnedFile = File.get(file_id)
return returnedFile
Python FLASK REST API functions
from PIL import Image
import magic
from base64 import b64encode
import io
accepted_mime_types = {'jpe':'image/jpeg','jpeg':'image/pjpeg','png':'image/png'}
def get(id):
return Product.query.filter(Product.id == id).one()
def create(inputFile, current_user):
filename = inputFile.filename
file_obj = File(
filename = filename,
extension = '.jpg',
folderpath = 'folderpath',
databinary = inputFile.read(),
category = 'default',
description = 'beschrijving...',
original_filename = filename,
created_by = current_user,
modified_by= current_user)
MAX_SIZE = (150, 150)
thumbnailFile, mimetype = File.getThumbnail(inputFile, MAX_SIZE)
if not thumbnailFile is None:
output = io.BytesIO()
thumbnailFile.save(output, format='PNG')
hex_data = output.getvalue()
file_obj.thumbnail = hex_data
else:
raise NameError(mimetype)
db.session.add(file_obj)
db.session.commit()
return str(file_obj.id)
def mimetype(file_obj):
return magic.from_buffer(file_obj.read(2048), mime=True)
def getThumbnail(file_obj, size):
file_obj.seek(0)
real_mime_type = magic.from_buffer(file_obj.read(2048), mime=True)
if (real_mime_type in accepted_mime_types.values()):
thumbnailImage = Image.open(file_obj)
thumbnailImage.thumbnail(size)
return thumbnailImage, real_mime_type
else:
raise NameError(real_mime_type)
I have a simple model, a serializer and a view. I want to upload a file over the view but no method I found worked.
Here's my code:
def test_api_post(self):
lesson = self.Create_lesson()
file = SimpleUploadedFile(
"file.txt",
"".join(random.choices(string.ascii_letters + string.digits, k=1024 * 5)).encode(),
"text/plain"
)
response = self.client.post(
"/api/submission/",
{
"lesson": lesson.id,
"file": file
},
format="multipart"
)
self.assertStatusOk(response.status_code) # Error
I tried it using with open() as file and I also tried using path.read_bytes(). Nothing worked.
How can I test binary file uploading with django-rest-framework's test client? doesn't work, https://gist.github.com/guillaumepiot/817a70706587da3bd862835c59ef584e doesn't work and how to unit test file upload in django also doesn't work.
I have fixed the problem with that:
import io
from django.test import TestCase
class test(TestCase):
def test_upload_file(self):
with open('/path/to/file.txt', 'rb') as fp :
fio = io.FileIO(fp.fileno())
fio.name = 'file.txt'
r = self.client.post('/url/', {'filename': fio, 'extraparameter': 5})
self.assertEqual(r.headers['Content-Type'], 'application/json')
url.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'/url/$', views.serverside_method, name="serverside_method")
]
Example on the server-side (view.py)
def serverside_method(request):
if 'filename' in request.FILES:
file_request = request.FILES['filename']
file_size = file_request.size
file_request_name = file_request.name
return JsonResponse({'Success': True})
else:
return JsonResponse({'Success': False})
source: https://gist.github.com/nghiaht/682c2d8d40272c52dbf7adf214f1c0f1
work for me
from rest_framework.test import APIRequestFactory
from apps.Some.SomeViewSet import SomeViewSet
c = APIRequestFactory()
url = 'someurl/'
view = SomeViewSet.as_view()
file = 'path/to/file'
q = {'filename': file}
request = c.post(url, q)
response = view(request)
here is what I would like to achieve:
I would like to be able to edit a database entry through a form which contains multiple different types of Fields (BooleandFields, StringFields etc.) and in these are two flask_wtf FileFields that I would like to have pre-populated (with the file name) when I would have already uploaded the files so I do not have to re-upload x copies of the same thing when I just want to change some entry in the other fields.
here is where I stand:
All the other fields (except the FileFields) are properly pre-populated when I enter the form to edit it.
I am able to upload a file with the combination of Flask-Uploads and UploadSet. through a flask_wtf.file FileField.
In my database I am saving the file name and the file url as Strings.
I have read the flask-wtf file upload as well as the WTForms documentation and I feel a bit lost with what I have to do to emulate what the form needs in order to have the FileField populated as if I already
Here are snippets of the code that I am using:
init.py
from flask import Flask
from config import Config
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_bootstrap import Bootstrap
from flask_uploads import UploadSet, configure_uploads
[...]
app = Flask(__name__)
[...]
csvfiles = UploadSet('csvfiles')
configure_uploads(app, (csvfiles,))
forms.py
The FileFields in question here are : "dive_posiview" and "dive_ctd"
from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileAllowed, FileRequired
from wtforms import StringField, IntegerField, DecimalField, SubmitField,BooleanField
from app import csvfiles
from app.models import User
import re
class DiveForm(FlaskForm):
nb = IntegerField('Dive Number', validators=[DataRequired()])
max_depth = IntegerField('Maximum Depth', validators=[DataRequired()])
launch = StringField("Launch Position: XX°XX.XXXX'N / XX°XX.XXXX'E ", validators=[InputRequired(),validate_Lat_Lon])
recovery = StringField("Recovery Position: XX°XX.XXXX'N / XX°XX.XXXX'E ", validators=[InputRequired(),validate_Lat_Lon])
launch_datetime = DateTimeLocalField('Launch Time',format='%Y-%m-%dT%H:%M', validators=[InputRequired()])
recovery_datetime = DateTimeLocalField('Recovery Time',format='%Y-%m-%dT%H:%M', validators=[InputRequired()])
bottom_start_datetime = DateTimeField('Bottom start time',format='%H:%M', validators=[DataRequired()])
bottom_start_depth = IntegerField('Bottom start depth', validators=[DataRequired()])
bottom_end_datetime = DateTimeField('Bottom end time',format='%H:%M', validators=[DataRequired()])
bottom_end_depth = IntegerField('Bottom end depth', validators=[DataRequired()])
dive_time_total = DateTimeField('Dive total time',format='%H:%M', validators=[DataRequired()])
dive_time_bottom = DateTimeField('Bottom total time', format='%H:%M',validators=[DataRequired()])
dive_posiview = FileField('Posiview log', validators=[FileAllowed(csvfiles, 'CSV file only !')])
dive_ctd = FileField('CTD log', validators=[FileAllowed(csvfiles, 'CSV file only ! ')])
[...]
submit = SubmitField('Validate')
routes.py
#app.route('/cruises/<cruisename>/<diveId>/edit',methods=['GET','POST'])
def dive_edit(cruisename,diveId):
try:
c = Cruises.query.filter_by(name=cruisename).first_or_404()
d = Dives.query.filter_by(cruise_id=c.id,id=diveId).first_or_404()
if request.method == "POST":
form = DiveForm(formdata = request.form)
if form.validate_on_submit():
dive = d
dive.nb = form.nb.data
dive.max_depth = form.max_depth.data
dive.launch = form.launch.data
dive.recovery = form.recovery.data
dive.launch_datetime = form.launch_datetime.data
dive.recovery_datetime = form.recovery_datetime.data
dive.bottom_start_datetime = form.bottom_start_datetime.data
dive.bottom_start_depth = form.bottom_start_depth.data
dive.bottom_end_datetime = form.bottom_end_datetime.data
dive.bottom_end_depth = form.bottom_end_depth.data
dive.dive_time_total = form.dive_time_total.data
dive.dive_time_bottom = form.dive_time_bottom.data
dive_folder = cruisename+'/Dive'+str(form.nb.data)
filename_posiview = csvfiles.save(request.files['dive_posiview'],folder=dive_folder)
url_posiview = csvfiles.url(filename_posiview)
filename_ctd = csvfiles.save(request.files['dive_ctd'],folder=dive_folder)
url_ctd = csvfiles.url(filename_ctd)
dive.posiview_filename = filename_posiview
dive.posiview_url = url_posiview
dive.ctd_filename = filename_ctd
dive.ctd_url = url_ctd
dive.sampling_nets = form.sampling_nets.data
dive.sampling_shovel = form.sampling_shovel.data
dive.sampling_drill = form.sampling_drill.data
dive.sampling_niskin = form.sampling_niskin.data
dive.sampling_push_cores = form.sampling_push_cores.data
dive.sampling_he_sampler = form.sampling_he_sampler.data
dive.sampling_arm_action = form.sampling_arm_action.data
dive.sampling_GBS = form.sampling_GBS.data
dive.sampling_GBC = form.sampling_GBC.data
dive.sampling_IMGAM = form.sampling_IMGAM.data
dive.sensor_CTD = form.sensor_CTD.data
dive.sensor_CODA = form.sensor_CODA.data
dive.sensor_sonar = form.sensor_sonar.data
dive.sensor_MiniPos = form.sensor_MiniPos.data
dive.sensor_MiniPos_calibrated = form.sensor_MiniPos_calibrated.data
dive.action_device_deployed = form.action_device_deployed.data
dive.action_device_recovered = form.action_device_recovered.data
dive.action_mosaicing = form.action_mosaicing.data
dive.action_3D_imaging = form.action_3D_imaging.data
db.session.commit()
# execute jupyter convert script for that dive
if filename_ctd is not None and filename_posiview is not None:
summary_file_path = os.path.abspath(os.curdir)+'/app/static/jupyter/scientific_summary_dive'+str(form.nb.data)+'.html'
if not path.exists(summary_file_path) :
paths = "POSIVIEW_PATH="+csvfiles_path+'/'+filename_posiview
paths += " CTD_PATH="+csvfiles_path+'/'+filename_ctd
thread = threading.Thread(target=os.system, args=( (paths+" jupyter nbconvert --to html --execute app/static/jupyter/dive_scientific_summary.ipynb --output scientific_summary_dive"+str(form.nb.data)),))
thread.daemon = True
thread.start()
return redirect(url_for('cruise',cruisename=cruisename))
else :
form = DiveForm(obj = d)
# NOT WORKING
if os.path.isfile(csvfiles_path+'/'+d.ctd_filename) :
form.dive_ctd.data = d.ctd_filename
# NOT WORKING
if os.path.isfile(csvfiles_path+'/'+d.posiview_filename) :
form.dive_posiview.data = d.posiview_filename
return render_template('dive_new.html',title='edit dive',form = form , diveId = diveId)
except Exception as e:
flash(e)
return render_template("500.html")
the versions that I am using are :
Python 3.8.2
Flask 1.1.1
Flask-Uploads 0.2.1
Flask-WTF 0.14.3
WTForms 2.3.1
Thanks for the help
I am using python-social-auth API for authentication for facebook in my website. But I am getting an exception.
while using 'apps.pipeline.save_profile'
'cannot import name save_status_to_session'
I am using django-pipeline version 1.6.13
This code in pipelne.py
def require_email(strategy, details, user=None, is_new=False, *args, **kwargs):
if kwargs.get('ajax') or user and user.email:
return
elif is_new and not details.get('email'):
email = strategy.request_data().get('email')
if email:
details['email'] = email
elif email is None:
error = "Sorry, but your social network (Facebook or Google)
needs to provide us your email address."
return HttpResponseRedirect(reverse('django.contrib.auth.views.login') + "?error=" + urllib.quote_plus(error))
else:
return redirect('require_email')
def save_profile(backend, details, response, uid,user, *args, **kwargs):
if backend.name == 'facebook':
url = "http://graph.facebook.com/%s/picture?type=large" % response['id']
avatar = urlopen(url)
profile = Profile.objects.filter(user_id=user.id)
if profile.count()==0:
profile = Profile(user_id=user.id)
else:
profile = Profile.objects.get(user_id=user.id)
profile.profile_image.save(slugify(user.username + " social") + '.jpg',
ContentFile(avatar.read()))
profile.save()
elif backend.name == 'google-oauth2':
if response.get('image') and response['image'].get('url'):
url = response['image'].get('url')
ext = url.split('.')[-1]
profile = Profile.objects.filter(user_id=user.id)
if profile.count()==0:
profile = Profile(user_id=user.id)
else:
profile = Profile.objects.get(user_id=user.id)
profile.profile_image.save(
'{0}.{1}'.format(user.username, ext),
ContentFile(urllib2.urlopen(url).read()),
save=False
)
profile.save()
And settings
SOCIAL_AUTH_PIPELINE = (
'social.pipeline.social_auth.social_details',
'social.pipeline.social_auth.social_uid',
'social.pipeline.social_auth.auth_allowed',
'social.pipeline.social_auth.social_user',
'social.pipeline.social_auth.associate_by_email',
'social.pipeline.user.get_username',
'polls.pipeline.require_email',
'social.pipeline.user.create_user',
'polls.pipeline.save_profile',
'social.pipeline.social_auth.associate_user',
'social.pipeline.social_auth.load_extra_data',
)
enter image description here
It's very hard to give a correct answer based on the very limited amount of information you provided. I'll give it a try based on the screenshot you linked.
First, it seems there is an attempt to import save_status_to_session from social_core.pipeline.partial in file social/pipeline/partial.py. The import error is not surprising, as social_core.pipeline.partial does not define these this function (see https://github.com/python-social-auth/social-core/blob/master/social_core/pipeline/partial.py).
The file social/pipeline/partial.py seems to correspond to a module that is no longer maintained (see https://github.com/omab/python-social-auth/blob/master/social/pipeline/partial.py and the README at the root of the repository).
As you import that module in mysite/polls/pipeline.py, I suggest to replace your import from social.pipeline.partial import partial by from social_core.pipeline.partial import partial.
I have a django backed website on Heroku and every time I try to view/download the upload excel files after uploading them on the Heroku website I get this error:
Not Found: The requested URL /excel_files/<file> was not found on this server.
Here is my views.py:
from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from .forms import UploadForm
from django.conf import settings
import os
import openpyxl, re
def index(request):
"""The home page which generates the donor list html page"""
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'].name
file_corrected = file.replace(" ", "_")
path = os.path.join(settings.MEDIA_ROOT, file_corrected)
wb = openpyxl.load_workbook(path)
sheet = wb.get_sheet_by_name('Sheet1')
text_file = open('upload/templates/upload/donor_list.html', 'w')
html1 = "{% extends 'upload/base.html' %}" + "\n" + "{% block header %}" + "\n" + " <h1>Donor List</h1>" + "\n" + "{% endblock header %}" + "\n" + "{% block content %}" + "\n"
html2 = "{% endblock content %}"
text_file.write(html1)
for rowNum in range(1, sheet.max_row + 1):
firstName = str(sheet.cell(row=rowNum, column=1).value)
if firstName == "None":
firstName = "\n"
lastName = str(sheet.cell(row=rowNum, column=2).value)
addNum = re.compile(r'\d(\d)*')
addressNumber1 = addNum.search(str(sheet.cell(row=rowNum, column=3).value))
if addressNumber1 is None:
addressNumber = ""
if addressNumber1 is not None:
addressNumber = addressNumber1.group(0)
donate = str(sheet.cell(row=rowNum, column=4).value)
donate = "$" + donate
if donate == "$None":
donate = ""
date = str(sheet.cell(row=rowNum, column=7).value)
year = date[2:4]
if year == "ne":
year = ""
if firstName == "\n" and lastName != "None":
firstName = str(sheet.cell(row=rowNum, column=2).value)
lastName = str(sheet.cell(row=rowNum, column=3).value)
addressNumber1 = addNum.search(str(sheet.cell(row=rowNum, column=4).value))
addressNumber = addressNumber1.group(0)
donate = str(sheet.cell(row=rowNum, column=5).value)
donate = "$" + donate
date = str(sheet.cell(row=rowNum, column=8).value)
year = date[2:4]
if firstName is "_" or lastName is "Anonymous":
text_file.write(""" <p>{} (Mr./Ms.) {} {} {}.</p>""".format(addressNumber, lastName, donate, year) + '\n')
else:
text_file.write(""" <p>{} {} {} {}.</p>""".format(addressNumber, firstName, donate, year) + '\n')
text_file.write(html2)
text_file.close()
return donor_list(request)
context = {'form': form}
return render(request, 'upload/index.html', context)
def instructions(request):
"""The how-to for file uploading"""
return render(request, 'upload/instructions.html')
def donor_list(request):
"""Webpage with the donor list after upload"""
return render(request, 'upload/donor_list.html')
and here is my settings.py as it relates to the Heroku website:
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
STATIC_URL = '/static/'
# Heroku settings
cwd = os.getcwd()
if cwd == '/app' or cwd[:4] == '/tmp':
import dj_database_url
DATABASES = {
'default': dj_database_url.config(default='postgres://localhost')
}
# Honor the "X-Forwarded_Proto' header for request.is.secure().
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
# Allow only Heroku to host the project
ALLOWED_HOSTS = ['WEBSITE_URL_HERE']
DEBUG = False
# Static asset configuration
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
STATIC_ROOT = 'staticfiles'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
)
MEDIA_ROOT = os.path.join(BASE_DIR, 'excel_files')
MEDIA_URL = '/excel_files/'
Notice that my views.py after upload displays the excel file as text using openpyxl module, but i find it odd that I can't seem to access these excel files on my Heroku admin page; they are listed but I can't download them as I described above. Beginner friendly answers are greatly appreciated.
You must not upload files to the filesystem on Heroku. As the documentation explains, the filesystem is ephemeral and is not shared between dynos. Anything uploaded will only be seen by the dyno that created it, and will be completely lost when that dunno restarts.
You must use a permanent store, for example S3.