Search code examples
djangoherokuamazon-s3collectstatic

Django + Heroku + S3: boto -> local variable "region_name" referenced before assignment


I'm getting a very strange error that got me really stuck for many hours now.

I did my deploy with Heroku for the first time and am using S3 for Media files. First thing I noticed was that I never had a migration working successfully after installing boto and django-storages-redux, not sure why. Anyway I kept going.

My configurations seemed to be working in AWS, since my staticfiles did go to my bucket the first time I tried it, but I got some img files not coming through, so I decided to reinstall boto and django-registration-redux (to see if it would migrate properly).

In the end it never migrated as expected and now I'm getting the following error:

UnboundLocalError: local variable 'region_name' referenced before assignment in my BOTO package when collectstatic.

I don't understand why migrate won't work and why I started to get this error when I re-installed boto and django-storages-redux.

terminal:

You have requested to collect static files at the destination
location as specified in your settings.

This will overwrite existing files!
Are you sure you want to do this?

Type 'yes' to continue, or 'no' to cancel: yes
Traceback (most recent call last):
  File "/Users/Alex/Desktop/Allugare/src/manage.py", line 22, in <module>
    execute_from_command_line(sys.argv)
  File "/Users/Alex/Desktop/allugare/lib/python3.5/site-packages/django/core/management/__init__.py", line 367, in execute_from_command_line
    utility.execute()
  File "/Users/Alex/Desktop/allugare/lib/python3.5/site-packages/django/core/management/__init__.py", line 359, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/Users/Alex/Desktop/allugare/lib/python3.5/site-packages/django/core/management/base.py", line 294, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/Users/Alex/Desktop/allugare/lib/python3.5/site-packages/django/core/management/base.py", line 345, in execute
    output = self.handle(*args, **options)
  File "/Users/Alex/Desktop/allugare/lib/python3.5/site-packages/django/contrib/staticfiles/management/commands/collectstatic.py", line 193, in handle
    collected = self.collect()
  File "/Users/Alex/Desktop/allugare/lib/python3.5/site-packages/django/contrib/staticfiles/management/commands/collectstatic.py", line 124, in collect
    handler(path, prefixed_path, storage)
  File "/Users/Alex/Desktop/allugare/lib/python3.5/site-packages/django/contrib/staticfiles/management/commands/collectstatic.py", line 349, in copy_file
    if not self.delete_file(path, prefixed_path, source_storage):
  File "/Users/Alex/Desktop/allugare/lib/python3.5/site-packages/django/contrib/staticfiles/management/commands/collectstatic.py", line 255, in delete_file
    if self.storage.exists(prefixed_path):
  File "/Users/Alex/Desktop/allugare/lib/python3.5/site-packages/storages/backends/s3boto.py", line 439, in exists
    if self.entries:
  File "/Users/Alex/Desktop/allugare/lib/python3.5/site-packages/storages/backends/s3boto.py", line 302, in entries
    for entry in self.bucket.list(prefix=self.location))
  File "/Users/Alex/Desktop/allugare/lib/python3.5/site-packages/storages/backends/s3boto.py", line 301, in <genexpr>
    self._entries = dict((self._decode_name(entry.key), entry)
  File "/Users/Alex/Desktop/allugare/lib/python3.5/site-packages/boto/s3/bucketlistresultset.py", line 34, in bucket_lister
    encoding_type=encoding_type)
  File "/Users/Alex/Desktop/allugare/lib/python3.5/site-packages/boto/s3/bucket.py", line 473, in get_all_keys
    '', headers, **params)
  File "/Users/Alex/Desktop/allugare/lib/python3.5/site-packages/boto/s3/bucket.py", line 399, in _get_all
    query_args=query_args)
  File "/Users/Alex/Desktop/allugare/lib/python3.5/site-packages/boto/s3/connection.py", line 668, in make_request
    retry_handler=retry_handler
  File "/Users/Alex/Desktop/allugare/lib/python3.5/site-packages/boto/connection.py", line 1071, in make_request
    retry_handler=retry_handler)
  File "/Users/Alex/Desktop/allugare/lib/python3.5/site-packages/boto/connection.py", line 927, in _mexe
    request.authorize(connection=self)
  File "/Users/Alex/Desktop/allugare/lib/python3.5/site-packages/boto/connection.py", line 377, in authorize
    connection._auth_handler.add_auth(self, **kwargs)
  File "/Users/Alex/Desktop/allugare/lib/python3.5/site-packages/boto/auth.py", line 755, in add_auth
    **kwargs)
  File "/Users/Alex/Desktop/allugare/lib/python3.5/site-packages/boto/auth.py", line 574, in add_auth
    string_to_sign = self.string_to_sign(req, canonical_request)
  File "/Users/Alex/Desktop/allugare/lib/python3.5/site-packages/boto/auth.py", line 514, in string_to_sign
    sts.append(self.credential_scope(http_request))
  File "/Users/Alex/Desktop/allugare/lib/python3.5/site-packages/boto/auth.py", line 496, in credential_scope
    region_name = self.determine_region_name(http_request.host)
  File "/Users/Alex/Desktop/allugare/lib/python3.5/site-packages/boto/auth.py", line 690, in determine_region_name
    return region_name
UnboundLocalError: local variable 'region_name' referenced before assignment

settings.py:

   ... 
   INSTALLED_APPS = (
        #DJANGO APPS
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.sites',
        'django.contrib.messages',
        'django.contrib.staticfiles',

        #THIRD PARTY APPS
        'allauth',
        'allauth.account',
        'allauth.socialaccount',

        #Social Authentications
        'allauth.socialaccount.providers.facebook',
        # 'allauth.socialaccount.providers.instagram',
        # 'allauth.socialaccount.providers.twitter',

        'crispy_forms',
        'django_messages',
        'storages',

        #MY APPS
        'lares',
        'mensagens',
        'profiles',
    )

    ...
    STATIC_URL = '/static/'
    STATIC_ROOT = os.path.join(BASE_DIR, "static-live", "static")


    MEDIA_URL = '/media/'
    MEDIA_ROOT = os.path.join(BASE_DIR, "static-live", "media")

    STATICFILES_DIRS = (
        os.path.join(BASE_DIR, "static"),
        )

    AWS_ACCESS_KEY_ID = "***"
    AWS_SECRET_ACCESS_KEY = "***"


    AWS_FILE_EXPIRE = 200
    AWS_PRELOAD_METADATA = True
    AWS_QUERYSTRING_AUTH = True

    DEFAULT_FILE_STORAGE = 'allugare.utils.MediaRootS3BotoStorage'
    STATICFILES_STORAGE = 'allugare.utils.StaticRootS3BotoStorage'
    # DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
    # STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
    AWS_STORAGE_BUCKET_NAME = 's3allugare'
    S3DIRECT_REGION = 'sa-east-1'
    S3_URL = '//%s.s3.amazonaws.com/' % AWS_STORAGE_BUCKET_NAME
    MEDIA_URL = '//%s.s3.amazonaws.com/media/' % AWS_STORAGE_BUCKET_NAME
    MEDIA_ROOT = MEDIA_URL
    STATIC_URL = S3_URL + 'static/'
    ADMIN_MEDIA_PREFIX = STATIC_URL + 'admin/'
    AWS_S3_HOST = 'sa-east-1.amazonaws.com'

    import datetime

    two_months = datetime.timedelta(days=61)
    date_two_months_later = datetime.date.today() + two_months
    expires = date_two_months_later.strftime("%A, %d %B %Y 20:00:00 GMT")

    AWS_HEADERS = {
        'Expires': expires,
        'Cache-Control': 'max-age=%d' % (int(two_months.total_seconds()), ),
    }

wsgi.py

"""
WSGI config for allugare project.

It exposes the WSGI callable as a module-level variable named ``application``.

For more information on this file, see
https://docs.djangoproject.com/en/1.10/howto/deployment/wsgi/
"""

import os
from django.core.wsgi import get_wsgi_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "allugare.settings")

application = get_wsgi_application()

utils.py

from storages.backends.s3boto import S3BotoStorage

StaticRootS3BotoStorage = lambda: S3BotoStorage(location='static') # S3 bucket name -> static
MediaRootS3BotoStorage  = lambda: S3BotoStorage(location='media')  # S3 bucket name -> static

Solution

  • Okay, here's the thing, if you're not using the default region of AWS you have to be careful when updating your region, since the S3's has different formats depending on the region.

    I'm in South America, thus I'm using sa-east-1 (for São Paulo).

    To me it worked when I changed the setting: AWS_S3_HOST = 'sa-east-1.amazonaws.com' to AWS_S3_HOST = 's3-sa-east-1.amazonaws.com'

    Enjoy!