Reputation: 43
Currently, the default Django FileField upload method with the application we host on app engine using Google Cloud SQL returns the following error:
OSError
[Errno 38] Function not implemented: '/base/data/home/apps/s~app/attachment-1.360717349796013945/media'
which is probably due to file writing being restricted in app engine and mkdir not working stated in Django debug mode:
/base/python27_runtime/python27_dist/lib/python2.7/os.py in makedirs
makedirs(head, mode)
except OSError, e:
# be happy if someone already created the path
if e.errno != errno.EEXIST:
raise
if tail == curdir: # xxx/newdir/. exists if xxx/newdir exists
return
mkdir(name, mode) ...
Therefore, I attempted to install django-filetransfer and the same error persists on Appengine.
Django setup:
Models
class OrderItemAttachmentForm(ModelForm):
class Meta:
model = OrderItemAttachment
exclude = ('item',)
def __init__(self, *args, **kwargs):
super(OrderItemAttachmentForm, self).__init__(*args, **kwargs)
Views
def RFO(request):
view_url = reverse('app.views.RFO')
elif 'saveLine' in request.POST:
order_attachment_form = OrderItemAttachmentForm(request.POST,request.FILES)
if order_attachment_form.is_valid():
order_attachment = order_attachment_form.save()
upload_url, upload_data = prepare_upload(request, view_url)
Template
{% load filetransfers %}
<form id="requestItemForm" name="requestItemSubmit" method="post" enctype="multipart/form-data" action="{{ upload_url }}">{% csrf_token %}{% render_upload_data upload_data %}
<div class="lineAttach">
<label for="id_attachment">Upload Attachment</label>
{{order_attachment_form.attachment}}
</div>
<button type="submit" id="saveLine" name="saveLine" class="btn grey doLoad right" value="Save Line Item">Save Line Item</button>
I have contemplated using Blobstore python API to store files as a blob or utilize Google Cloud Storage but do not know how to integrate it into Django models. Any help would be appreciated, thanks!
Upvotes: 2
Views: 559
Reputation: 2195
I know this was posted a long time ago, but the answer is pretty straightforward (even though it's not obvious):
Your ModelForm is fine, but you can actually remove the __init__
function as all it does is pass details to the parent class which happens anyway.
Your view needs to do a couple specific things: prepare_upload to get the proper upload URL, and handle both GET and POST cases (the Blobstore will perform a callback to your form once the file has been uploaded. If you use class-based views, it might look something like this:
class OrderAttachmentView(FormView):
def get(self, request):
upload_url, upload_data = prepare_upload(
request,
reverse('attachment-upload'),
private=True,
)
form = OrderItemAttachmentForm()
return render(
request,
'attachment_form.html',
{
'form': form,
'upload_url': upload_url,
'upload_data': upload_data,
},
)
def post(self, request):
form = OrderItemAttachmentForm(request.POST, request.FILES)
order_item_attachment = form.save()
return HttpResponseRedirect(reverse(
'attachment-detail',
kwargs={'pk': order_item_attachment.id},
))
Your form needs the custom action parameter:
{% load filetransfers %}
<form action="{{ upload_url }}" method="POST" enctype="multipart/form-data">
...
<input type="submit" value="Upload" />
</form>
Upvotes: 0
Reputation: 1003
I'm having a same trouble. I think django-filetransfer needs djangoappengine to operate properly. I'm now taking a different approach to solve the problem. It's too bad that I can't use such a convenient tool.
Upvotes: 1