Using Django2 and nginx, users can upload files (mainly pic,vids) and I want to serve those files by masking the full url path.
This is the example structure I expect to see but I don't want users to know about this structure or even the image filename.
domain.com/media/user/pictures/Y/M/D/image1.jpg
I want the user to see the above image through a url like this and the random UUID number changes for each file and that number can point to any type of file.
domain.com/media/23kj23l9ak3
When the file is uploaded the original name, permissions assigned (public, friends, private), file path and the UUID that is generated stored in the database) but the file is stored on the filesystem or remote location.
I've never got to this point before and I would like to know what the modern way of doing it would be or let me know what technology/features of django/nginx can help me solve it.
I'm not entirely sure why you want to do this, rather than simply using the UUID as the filename of the uploaded file, but you certainly can do it.
One good way would be to route the request via Django, and use the custom X-Accel-Redirect header to tell nginx to respond with a specific file. You would need to store both the UID and the actual path in a Django model. So the nginx config would be something like:
location /protected/ {
internal;
alias /media/user/; # note the trailing slash
}
and the Django view would be:
def user_picture(request, uuid):
image = MyModel.objects.get(uuid=uuid)
response = HttpResponse(status=200)
response['X-Accel-Redirect'] = '/protected/' + image.file.path
return response
Related
Problem is i have hosted at pythonanywhere using django.Video is downloaded at pythonanywhere server and user/client system too.Thats why i used os. remove(path).After downloading it removes from server.
Is there any ways files donot write on pyhtonanywhere server. so that i donot use os.remove(path).
How to restrict to write at pythonanywhere server. Only to download at user system.
def fb_download(request):
link = request.GET.get('url')
html= requests.get(link)
try:
url= re.search('hd_src:"(.+?)"',html.text)[1]
except:
url= re.search('sd_src:"(.+?)"',html.text)[1]
path=wget.download(url, 'Video.mp4')
response=FileResponse(open(path, 'rb'), as_attachment=True)
os.remove(path)
return response
If I understand correctly, you're trying to get a request from a browser, which contains a URL. You then access the page at that URL and extract a further URL from it, and then you want to present the contents of that second URL -- a video -- to the browser.
The way you are doing that is to download the file to the server, and then to serve that up as a file attachment to the browser.
If you do it that way, then there is no way to avoid writing the file on the server; indeed, the way you are doing it right now might have problems because you are deleting the file before you've returned the response to the browser, so there may (depending on how the file deletion is processed and whether the FileResponse caches the file's contents) be cases where there is no file to send back to the browser.
But an alternative way to do it that might work would be to send a redirect response to the URL -- the one in your variable url -- like this, without downloading it at all:
def fb_download(request):
link = request.GET.get('url')
html= requests.get(link)
try:
url= re.search('hd_src:"(.+?)"',html.text)[1]
except:
url= re.search('sd_src:"(.+?)"',html.text)[1]
return redirect(url)
By doing that, the download happens on the browser instead of on the server.
I don’t understand javascript really good,
But i think if you download the file to the server
And then you can download the file to the use using JS
And i think you can use
I am new to AWS and using S3 to host my static website! I have an html file, page.html and it should be acessible at mydomain.com/page. However, it is only accessible at mydomain.com/page.html :(. How can I fix this?
Unfortunately if you want this to work there are a couple of solutions that you can try.
For the first by creating an index document in a subfolder i.e. /page/index.html you would be able to access your site on /page/. This would work well if you're using a hierarchy.
However, if you have many many pages then you will need to use another solution that can rewrite the client site URL to your .html file.
For this you can use CloudFront with a Lambda#Edge function to perform this in the Origin Request stage. This function might look similar to the below.
import json
import os
def lambda_handler(event, context):
request = event['Records'][0]['cf']['request']
filepath, extension = os.path.splitext(request['uri'])
if not extension:
new_uri = request['uri'] + '.html'
request['uri'] = new_uri
return request
By doing this your users will see a nice clean path but when it goes to your origin it will append the extension.
Please try adding ".htaccess" file in root directory folder with the following code
#Make pages render without their extension in the URL
Options +MultiViews
Is there a way to make some files unaccessible via direct url? For example, an image appears on a page but the image location doesn't work on it's own.
How Things Normally Work
By default, all static and media files are served up from the static root and media root folders. A good practice is to have NGINX or Apache route to these, or to use something like Django Whitenoise to serve up static files.
In production, you definitely don't want to have the runserver serving up these files because 1) That doesn't scale well, 2) It means you're running in DEBUG mode on production which is an absolute no-no.
Protecting Those Files
You can keep this configuration for most files that you don't need to protect. Instead, you can serve up files of your own within Django from a different filepath. Use the upload_to parameter of the filefield to specify where you want those files to live. For example,
protectedfile = models.FileField(upload_to="protected/")
publicfile = models.FileField(upload_to="public/")
Then in NGINX make your block direct to /var/www/myproject/MEDIAROOT/public instead. That will enable you to continue serving up public files.
Meanwhile, for the protected files, those can be served up by the view with:
def view_to_serve_up_docs(request, document_id):
my_doc = MyDocumentModel.objects.get(id=document_id)
# Do some check against this user
if request.user.is_authenticated():
response = FileResponse(my_doc.privatefile)
response["Content-Disposition"] = "attachment; filename=" + my_doc.privatefile.name
else:
raise Http404()
return response
And link to this view within your templates
<a href='/downloadFileView/12345'>Download File #12345 Here!</a>
Reference
More about the FileResponse object: https://docs.djangoproject.com/en/1.11/ref/request-response/#fileresponse-objects
How to configure Django and Cherokee to serve media (user uploaded) files from Cherokee but to logged in users only as with #login_required on production.
Create a Django view which servers the file
Use #login_required on this view to restrict the access
Read the file from the disk using standard Python io operations
Use StreamingHttpResponse so there is no latency or memory overhead writing the response
Set response mimetype correctly
I will answer my own question
As you are using Cherokee
Remove direct access to media folder with the media URL as localhost/media/.. for exemple by removing the virtuelhost serving it
Activate (check) Allow X-Sendfile under Handler tab in Common CGI Options in the virtuelserver page that handle Django request.
Let's say you have users pictures under media/pictures to protect that will be visible to all users only. (can be modified as you want just an exemple)
Every user picture is stored in media/pictures/pk.jpg (1.jpg, 2.jpg ..)
Create a view :
#login_required(redirect_field_name=None)
def media_pictures(request,pk):
response = HttpResponse()
path=os.path.join (settings.MEDIA_ROOT,'pictures',pk+'.jpg')
if os.path.isfile(path):
#response['Content-Type']="" # add it if it's not working without ^^
response['X-Accel-Redirect'] = path
#response['X-Sendfile'] = path # same as previous line,
# X-Accel-Redirect is for NGINX and X-Sendfile is for apache , in our case cherokee is compatible with two , use one of them.
return response
return HttpResponseForbidden()
Cherokee now take care of serving the file , it's why we checked the Allow X-Sendfile , this will not work without
path variable here is the full path to the file, can be anywhere , just read accsible by cherokee user or group
4. Url conf
As we disable direct access of Media folder, we need to provide an url to access with from Django using the previous view
for exemple , To make image of user with id 17 accessible
localhost/media/pictures/17.jpg
url(r"^media/pictures/(?P<pk>\d+)\.jpg$", views.media_pictures,name="media_pictures"),
This will also work for Apache, Nginx etc , just configure your server to use X-Sendfile (or X-Accel-Redirect for Nginx), this can be easily found on docs
Using this, every logged user can view all users' pictures , feel free to add additional verifications before serving the file , per user check etc
Hope it will help someone
I store a lot of files, using a hash as file name, but when a user wants to download it, I would like to be able to give the file a new name.
Let's say the user navigates to www.myurl.com/userxy/files/some.pdf. In the Django View for that url, I can now look up the correspondig file, which might be on the server on .../files/46dfa12bbf32d523fbb3642dfee45bb4.
So how can I now get this file to be served as some.pdf to the client? Do I have to copy the file first, and giving it a different name on the disc or can I somehow serve the original file? Is what I'm trying at all good practice?
I also don't know on what level (Apache or Django) this type of operation is best handled. But since I didn't find anything about this for Apache or Django, I would be interested in solutions for either of them.
Quoting django docs Telling the browser to treat the response as a file attachmen, you should inform it in response:
>>> response = HttpResponse(my_data, content_type='application/vnd.ms-excel')
>>> response['Content-Disposition'] = 'attachment; filename="some.pdf"'