Django private file upload

2019-02-28 17:00发布

问题:

I would like admin users to be able to attach private arbitrary files related to my models a la Share Point. As Django is primarily used as a publication platform, all of the examples I've found so far upload files to the static directory, where they are publicly accessible. How can I allow an admin to upload files that have the same auth permissions as the model they are related to?

回答1:

What you can do is set a certain location in your web server that is classified as internal only, with business logic in your Django application that will send a redirect with a certain header that will allow your web server to serve the file statically.

I have previously done this with Nginx using X-Accel-Redirect so I am going to use that for my example, but I believe there is equivalent functionality in Apache2 and other web servers (X-Sendfile, I think?).

In your Nginx config, set up a location that serves the directory where you are uploading your access-protected files:

location /protected/ {
    internal;
    alias /var/www-priv/;
}

Files in this directory will not be accessible externally at the URL of /protected/{filepath}, but will be if you return a response from your Django application with the header X-Accel-Redirect = /protected/{filepath}.

Create a view with a url like /media/{filepath} in which you perform the necessary business logic to control access to it (you may want to make the path params slightly more detailed such that you can capture the app label, model and object ID which the file is attached for the purposes of access control e.g. /media/{app_label}/{model}/{object_id}/{filename})

You then just do

response = HttpResponse()
response['X-Accel-Redirect'] = "/protected" + filepath
return response

and Bob's your uncle - the user will be served the protected file.



回答2:

I think the most powerful way to do this is writing a custom file storage

It's no so difficult (but may be overkill for your needs). Then you can bind your custom storage to your model in this way:

from django.db import models
from django.db.models.fields.files import FileField
from myapp.storage import MyCustomStorage

class MyModel(models.Model):
    path = FileField( ... , storage=MyCustomStorage(), blank=False)

Then, you can implement the business logic in your custom storage class. Doing this, you can store your private files on a local file system, data base, or in a remote system like Google AppEngine.

Cheers!