0đź‘Ť
The issue is with the Windows operating system Path. I tried with the same settings in Ubuntu. It’s working there flawlessly.
3đź‘Ť
The other answers aren’t quite correct about why this error is happening. The dropbox storage object back-end uses a django utility (django.utils._os.safe_join)
to verify a filename for the target operating system. See the code here
Even though you pass the upload_to
argument which gives a unix-style path (something like /save/path) the django utility makes sure the root of that save path matches the base path for the operating system :(. The dropbox SDK does not like a drive prefixed to the desired save path (AKA C:/path/file.name is not a valid save directory for dropbox).
To make this work on Windows make sure you do a couple things
First, modify the storage back-end _full_path method like this (or create your own subclass).
def _full_path(self, name):
if name == '/':
name = ''
print('Root path in dropbox.storage : ', self.root_path)
# If the machine is windows do not append the drive letter to file path
if os.name == 'nt':
final_path = os.path.join(self.root_path, name).replace('\\', '/')
# Separator on linux system
sep = '//'
base_path = self.root_path
if (not os.path.normcase(final_path).startswith(os.path.normcase(base_path + sep)) and
os.path.normcase(final_path) != os.path.normcase(base_path) and
os.path.dirname(os.path.normcase(base_path)) != os.path.normcase(base_path)):
raise SuspiciousFileOperation(
'The joined path ({}) is located outside of the base path '
'component ({})'.format(final_path, base_path))
# TODO Testing
print('Full file path in storage.dropbox._full_path : ', final_path)
return final_path
else:
return safe_join(self.root_path, name).replace('\\', '/')
Second, make sure you are passing the content and name to the model FileField. I had troubles when I did not explicitly pass the file contents and name (something about the uploaded file context retaining the file name?). I re-implemented my models save method like this
def save(self, *args, **kwargs):
# Save file
## Save raw entry from user ##
# Extract files contents
try:
uploaded_raw_entry = kwargs['upload_raw_entry']
except KeyError:
raise UploadError(('No file was passed from the admin interface. ' +
'Make sure a ContentFile was passed when calling this models save method'))
# Test raw_directory_path TODO Remove after testing
print('Raw entry name from model.save : ', raw_directory_path(self, uploaded_raw_entry.name))
with uploaded_raw_entry.open(mode='rb') as f:
raw_entry_content = f.read()
raw_entry_file = ContentFile(content=raw_entry_content.encode('utf-8'),
name=raw_directory_path(self, uploaded_raw_entry.name))
# Save the content file into a model field
raw_entry_file.open(mode='rb')
self.raw_entry.save(raw_entry_file.name, raw_entry_file, save=False)
raw_entry_file.close()
This definitely is workable from Windows, but with extra steps 🙂
- [Django]-How to use Django QuerySet.union() in ModelAdmin.formfield_for_manytomany()?
- [Django]-How much dog food should one eat? – Internal and External RestAPI & Oauth2
- [Django]-What's gettext_lazy on django is for?
2đź‘Ť
This error message is coming from the Dropbox API, indicating that the “path” supplied for the Dropbox API call doesn’t have the expected format. E.g., if you’re uploading a file, the “path” you supply would be the path in the Dropbox account where you want to put the uploaded data.
You’re supplying the value:
D:/media/10506738_10150004552801856_220367501106153455_o.jpg
(That seems to be a local Windows filesystem path.)
The Dropbox path you supply should instead look something like:
/media/10506738_10150004552801856_220367501106153455_o.jpg
(That would be a path relative to the Dropbox root. It doesn’t have a drive letter.)
You’ll need to dig in to your code to see where/why that incorrect type of path is being supplied to Dropbox.
- [Django]-FullCalendar and django
- [Django]-How to import data from scanned text into Django models
- [Django]-How to create uuid4 file names for images uploaded with Django-CKEeditor?
1đź‘Ť
I encountered this issue also on my Linux workstation – so the equivalent Linux answer for @greg’s answer is to add a "/"
to your backup name:
import sys, os
import dropbox
from dropbox.files import WriteMode
from dropbox.exceptions import ApiError, AuthError
# Add OAuth2 access token here.
TOKEN = '<your-token>'
data_path = './data_files'
filename = 'my-file-backup.txt'
BACKUPPATH = "/"+filename # <----- This should do the trick!
# Uploads contents of filename to Dropbox
def backup():
current_file_path = os.path.join(data_path, filename)
with open(current_file_path, 'rb') as f:
print("Uploading " + filename + " to Dropbox as " + BACKUPPATH + "...")
try:
dbx.files_upload(f.read(), BACKUPPATH, mode=WriteMode('overwrite'))
except ApiError as err:
if (err.error.is_path() and
err.error.get_path().reason.is_insufficient_space()):
sys.exit("ERROR: Cannot back up; insufficient space.")
elif err.user_message_text:
print(err.user_message_text)
sys.exit()
else:
print(err)
sys.exit()
So, the error message is quiet confusing – the file name and path in question is not your local but the Dropbox remote file name and path.
- [Django]-Check if each value within list is present in the given Django Model Table in a SINGLE query
- [Django]-Django model field storing a function or class
- [Django]-Django: Add field to model formset
- [Django]-What does 'serializer.initial_data' mean?
- [Django]-How to run two django apps in same server with different dynamic DJANGO_SETTINGS_MODULE env variables