Django-storages upload FileField and ImageField to Dropbox - python

(Django 2.0, Django Rest Framework 3.8, Python 3.6, Django Storages 1.7, Dropbox 9.1)
I'm trying to upload a file to the Dropbox App Folder I've created, but I run into the same error at every attempt:
C:/TrainerPics/UI_4.png' did not match pattern '(/(.|[\r\n])*|id:.*)|(rev:[0-9a-f]{9,})|(ns:[0-9]+(/.*)?)'
On the Dropbox dashboard from desktop, the folder I want to upload to is shown as:
Dropbox > Apps > DjangoAppNameHere
Here's my setup in settings.py:
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATIC_URL = '/static/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
DEFAULT_FILE_STORAGE = 'storages.backends.dropbox.DropBoxStorage'
DROPBOX_OAUTH2_TOKEN = 'some_token_here'
where storages is also listed in installed apps. Here's the model field I'm trying to upload:
trainer_profile_pic = models.ImageField(upload_to="TrainerPics/", null=True, blank=True)
I've tried this both with and without the / character, and tried this using upload_to=DjangoAppNameHere both with FileField and ImageField with no success. The documentation for Dropbox is rather sparse in the django-storages package, and doesn't describe how to set up a field to get it working.

That error message is coming from the Dropbox API, and it's indicating that the supplied path doesn't match the expected format. That is, when uploading to Dropbox via the Dropbox API, you're expected to supply the desired path for the uploaded file, in a format that matches the supplied pattern.
The most commonly used format for that is the first portion of that pattern, which is just a "/"-delimited path for the remote path relative to the root in Dropbox. For example: '/TrainerPics/UI_4.png'.
Based on the output, you're instead supplying a path that looks like a local Windows filesystem path: 'C:/TrainerPics/UI_4.png'.
You'll need to update the app/configuration to supply the remote path instead.

This is an old question, just to help people who might have similar problems.
There are two options that I used.
Use a linux machine when uploading your files. This will allow the API to upload your image as it's probably the same filesystem as their servers.
Only use the DROPBOX API on the server, and use local filestorage on local development. Servers run on unix and it does not produce the error.

Related

Can Django STATIC_ROOT point to path on another server?

I am using Django 4.0.1 in my project, and right prior to deploying my site, I am faced with the issue of handling my static files. Due to the limit of my server, I have decided to instead serve these static files via CDN.
I have already configured my STATIC_URL option in settings.py:
STATIC_URL = 'assets/'
I am aware that in the Django documentation, they say that this url refers to the static files located in STATIC_ROOT. Of course, normally the latter is an absolute path on your server where the collectstatic command collects the static files and put them there, but I am wondering if I can configure this STATIC_ROOT to point a path which is not on my server.
To be precise, I want to know whether I can point STATIC_ROOT to my CDN storage. In that way I can still use STATIC_URL to refer to my static assets, while being able to serve them via CDN.
Yes, it's actually a recommended way to serve static files for years. Not sure why Django didn't add it to its core.
You can use django-storages, it supports almost every cloud provider. You can use it for media and/or static.
Yes definitely you can use it for any other server. For example while we use AWS S3 as a server to serve static files it should look like this :
USE_S3 = os.getenv('USE_S3') == 'TRUE'
if USE_S3:
# aws settings
AWS_ACCESS_KEY_ID = os.getenv('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = os.getenv('AWS_SECRET_ACCESS_KEY')
AWS_STORAGE_BUCKET_NAME = os.getenv('AWS_STORAGE_BUCKET_NAME')
AWS_DEFAULT_ACL = 'public-read'
AWS_S3_CUSTOM_DOMAIN = f'{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com'
AWS_S3_OBJECT_PARAMETERS = {'CacheControl': 'max-age=86400'}
# s3 static settings
AWS_LOCATION = 'static'
STATIC_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/{AWS_LOCATION}/'
STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
else:
STATIC_URL = '/staticfiles/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')

Django. Using .ini files in code folder

I wanted to have a .py file using a ConfigParser class to recover information from a .ini file (containing URLs for a 3rd party REST service) Until now this worked since it was finding the file, but now it's not. App structure is:
app
folder
file.py
urls.ini
I assume this is due to my static files settings, which are as following:
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATIC_URL = '/static/'
# Extra places for collectstatic to find static files.
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
)
This is because I wanted to mantain settings that were compatible for both local development and web production escenarios (for which I could probably test with code in the web) for Heroku. I wanted to make it so I didn't have to change much stuff.
Thanks in advance.
If you're trying to read some files, you have to get the route.
If you have your static folder in your Django folder it could be easy to get your .ini file doing this
ini = open("%s/folder/yourfile.ini" % BASE_DIR, "r")
And then read your file lines.
In my opinion using a .py file for configuration it's easier than .ini file, and you can have many of them and load depending of a settings.py parameter for example.
Edit: for using Django config file variables
from django.conf import settings
BASE_DIR = settings.BASE_DIR

Django FileBrowser 400 Error

I'm getting a 400 error when trying to access the /admin/filebrowser/browse/ page. I followed the instructions as per https://django-filebrowser.readthedocs.org/en/3.5.2/quickstart.html and have my URLs and installed apps configured correctly.
What I'm not too sure about are the media paths in settings.py;
FILEBROWSER_DIRECTORY = os.path.join(BASE_DIR, '/ogencat/MEDIA/uploads')
FILEBROWSER_MEDIA_ROOT = os.path.join(BASE_DIR, '/ogencat/MEDIA')
FILEBROWSER_MEDIA_URL = '/MEDIA/'
I have folder in my workspace called MEDIA and a folder within called uploads.
I wasn't too sure about what the docs wanted me to do in terms of setting these paths - I hadn't seen the getattr(settings, "FILEBROWSER_MEDIA_ROOT", settings.MEDIA_ROOT) syntax before so I just added the paths as I have done for the rest of settings.py
Thanks!
You need to add trailing slashes
Directories must exist prior accessing them

django-pipeline amazon s3 collectstatic file could not be found

I am using s3boto, django-pipeline and django-storages with this setting:
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
STATICFILES_STORAGE = 'utils.classutils.S3PipelineStorage'
MEDIA_ROOT = "/"
MEDIA_URL = '//s3.amazonaws.com/%s/' % AWS_STORAGE_BUCKET_NAME
STATIC_ROOT = '/static/'
STATIC_URL = '//s3.amazonaws.com/%s/static/' % AWS_STORAGE_BUCKET_NAME
STATICFILES_DIRS = (
os.path.join(SITE_ROOT, 'assets'),
)
and this custom storage for django-pipeline
from django.contrib.staticfiles.storage import CachedFilesMixin
from pipeline.storage import PipelineMixin
from storages.backends.s3boto import S3BotoStorage
class S3PipelineStorage(PipelineMixin, CachedFilesMixin, S3BotoStorage):
pass
but I keep on getting:
ValueError: The file 'project/head.png' could not be found with <utils.classutils.S3PipelineStorage object at 0x2163510>.
but this file does not exist anywhere! not in plugins, I tried finding it, I checked my static dirs, tried finding it in admin, and I don't even remember working with a file named like this! I tried findstatic and the file can't be found.
What could I be missing?
You certainly have a css file that point to a non-existing 'project/head.png' file, remove this reference, and it should work.
Short tip. I encountered this when I was setting up S3 for serving static files.
I wanted to serve static content from s3 and keep handling uploaded files to the media folder on the local machine. What I had then was one image that was referenced in a css-file on s3 that was pointing to an image in the media folder like this background: url(../media/some/image.png).
Obviously that file could not be found in s3 with the relative path that was set in the css and the upload crashed. It works locally but not when running staticfiles from s3.

Proper way to handle static files and templates for Django on Heroku

I'm moving over my django app to Heroku, and I was wondering what the proper way to handle static files is. Do I just push them via git to Heroku? Or should I be storing them on SW3 or something? Also, what should the STATIC_ROOT and such be?
Thanks!
You should store them externally on a service like S3 - while Heroku can serve static files, it's not designed to.
Here's a good primer on getting started with S3:
https://devcenter.heroku.com/articles/s3
Use django-storages http://django-storages.readthedocs.org/en/latest/index.html to collect static files to your S3 bucket and serve them accordingly.
These are the necessary settings you'll need to have for S3:
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
STATICFILES_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
AWS_ACCESS_KEY_ID = 'access-id'
AWS_SECRET_ACCESS_KEY = 'secret-key'
AWS_STORAGE_BUCKET_NAME = 'bucket-name'
AWS_PRELOAD_METADATA = True # necessary to fix manage.py collectstatic command to only upload changed files instead of all files
MEDIA_ROOT and STATIC_ROOT are superceded by DEFAULT_FILE_STORAGE and STATICFILES_STORAGE respectively and hence not needed. You will, however, want to set MEDIA_URL and STATIC_URL to something like
STATIC_URL = 'https://bucket-name.s3.amazonaws.com/static/'
ADMIN_MEDIA_PREFIX = 'https://bucket-name.s3.amazonaws.com/static/admin/'
If you want to store your static and media files in different subfolders, this is a great solution: https://stackoverflow.com/a/10825691/674794
You'll want to set MEDIA_URL and STATIC_URL to the respective new folders, e.g.
MEDIA_URL = 'https://bucket-name.s3.amazonaws.com/media/'
STATIC_URL = 'https://bucket-name.s3.amazonaws.com/static/'
You'll also want to manually execute manage.py collectstatic and disable Heroku's automatic collectstatic as per https://devcenter.heroku.com/articles/django-assets#disabling_collectstatic, as Heroku's collectstatic will reupload every static file to S3 every time you push even if the files haven't been modified, adding a hefty transfer and request load to S3 and slowing down your pushes.
Then just continue using {{ STATIC_URL }} in your templates like usual and you should be set!
<link href='{{ STATIC_URL }}css/styles.css' type='text/css' rel='stylesheet'>
If you want to start off simple and choose not to immediately take that route though, you can do the quick hack in your urls configuration by following Cesar's mentioned post at Heroku - Handling static files in Django app, though there'll be a significant decrease in app performance.
While #Intenex's answer might still be the way to go if you have a lot of static content, for getting started, Heroku suggests using Whitenoise.
Here's Heroku's article aptly entitled "Django and Static Assets".
And the whitenoise documentation itself has a nice section on "Shouldn’t I be pushing my static files to S3 using something like Django-Storages?"

Categories