1

In a nutshell, we are trying to implement the following example from Google using Django:

from google.appengine.ext import blobstore
from google.appengine.ext.webapp import blobstore_handlers

class MainHandler(webapp2.RequestHandler):
  def get(self):
    upload_url = blobstore.create_upload_url('/upload')
    self.response.out.write('<html><body>')
    self.response.out.write('<form action="%s" method="POST" enctype="multipart/form-data">' % upload_url)
    self.response.out.write("""Upload File: <input type="file" name="file"><br> <input type="submit"
        name="submit" value="Submit"> </form></body></html>""")

class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
  def post(self):
    upload_files = self.get_uploads('file')  # 'file' is file upload field in the form
    blob_info = upload_files[0]
    self.redirect('/serve/%s' % blob_info.key())

Our app is written in Django 1.x. We use urls.py, views.py and models.py to define our url scheme, views and data models respectively.

In our database, we need to keep track of the data file (or at least, a reference to where the file exists on disk). Currently, our data model is as follows:

class FileData(models.Model):
    token                   = models.CharField(max_length=10)
    file                    = models.FileField(upload_to=get_upload_file_name, null=True, default=None, blank=True)

The field 'token' contains a token that client apps will use to request the file for download. The field 'file' is intended to contain the data. However, if we need to make it a reference to a blob location, it won't be a problem. We just don't know what to do at this point. What is the right solution?

Our urls pattern is as follows:

urlpatterns = patterns('',
    url(r'^upload/', 'views.upload', name='upload'),
    url(r'^/serve/([^/]+)?', 'views.servehandler', name='servehandler'),
)

Our form is as follows.

class DataUploadForm(forms.Form):
    """
    FileData form
    """
    token = forms.CharField(max_length=10)
    file = forms.FileField()

    class Meta:
        model = FileData
        fields = ['token', 'file', ]


    def __init__(self, *args, **kwargs):
        super(DataUploadForm, self).__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.form_tag = False
        self.helper.layout = Layout(
            'token',
            'file',
            ButtonHolder(
                Submit('submit', 'Submit', css_class='btn btn-success btn-block'),
            ),

        )

Our view is as follows.

def upload(request):
    args = {}
    args.update(csrf(request))
    if request.method == 'POST':
        print "In /upload"
        form = DataUploadForm(request.POST, request.FILES)
        if form.is_valid():
            file_data = FileData()
            file_data.token = request.POST.get('token')
            file_data.file = request.FILES.get('file')
            print "===========> Uploading:" + file_data.token
            file_data.save()
            return render(request, 'upload_success.html', args)

    form = DataUploadForm()
    args['form'] = form
    return render(request, 'upload.html', args)

When we execute, we get:

Exception Value:    
[Errno 30] Read-only file system: u

What are we doing wrong? How can we improve our code? How do we get Google App Engine to save our file, perhaps in the blobstore, and give us the reference to where the file exists for use in downloading it later?

Please be complete. Describe changes needed for urls.py, models.Model, views.py and yaml files (if necessary). Address how to upload large files (i.e., files greater than 40 MB each).

Please don't send us any more links. We have searched and seen a lot of postings-- none of which answers this question. If you can, please post a code snippets that answer the question -- not links.

Sunny
  • 1,464
  • 14
  • 26

1 Answers1

2

The reason you have this Read-only file system error is that the default models.FileField save uploaded file to the MEDIA_ROOT folder and it's read-only for Google Appengine apps.

You have to use a third party FileField to save the uploaded files to services like Google Cloud Storage or Amazon S3.

I did a quick search and found:

And for the upload file size limit issue, Google Appengine has a size limit for request which is 32M. To support larger files, you have to make the user upload their files directly to BlobStore or Google Cloud Storage and build a callback handler to link the uploaded file with your model.

Check these links:

Community
  • 1
  • 1
adieu
  • 714
  • 3
  • 12
  • Please note that I quoted the code from the links you provided. We are asking for how to do the same thing using python/django setup and not the webapp2.RequestHandler. Note the first paragraph of our question here: "In a nutshell, we are trying to implement the following example from Google using Django." Please don't send any more links. We have searched and seen them all. If you can, please post an example code that answers the question -- not links. – Sunny Nov 03 '14 at 20:07
  • I think my answer if pretty straight forward. Anyone with decent Python/Django skill should be able to accomplish it by himself. For the first part, just replace your FileField. For the second part, just write a view which renders the form as the example code does and write another view as the callback handler. I can and I have done this before. But I just don't want to write it out since I come to SO to answer questions for fun instead of write other people's code for free. – adieu Nov 03 '14 at 21:00
  • The body of our question contains the view "upload"--which we wrote. Can you fix it--instead of condesending? – Sunny Nov 03 '14 at 21:02
  • My goodness! You are quite insulting. Our entire site uses django-crispy forms. I copied the code as it existed on our site when I posted the question. If the form is confusing you, forget it. The important thing is that we submit a form--which calls "upload" view when the form is submitted. Now, do you have any constructive answers for the question? – Sunny Nov 03 '14 at 21:45
  • I'm sorry if you find my ANSWERS insulting. I'm just pointing you to the right direction and hope you could find the REAL problem yourself. Just read the `MainHandler` carefully. It renders a form but the `action` property is equal to the result of `blobstore.create_upload_url('/upload')` and you will find that value just points to a Google's server instead of your application. And if you check HTML SPEC again, you'll find that means when the form submitted the request will goes to Google's server. Then look at your code again, it renders a form and points to your app. So you find the PROBLEM. – adieu Nov 03 '14 at 21:59
  • Great answer @adieu. Thanks! – Randall Dec 30 '17 at 23:56