Django-storages और Amazon S3 के साथ Django परियोजना कैसे स्थापित करें, लेकिन स्थिर फ़ाइलों और मीडिया फ़ाइलों के लिए अलग-अलग फ़ोल्डरों के साथ?


92

मैं एक Django परियोजना को कॉन्फ़िगर कर रहा हूं जो सर्वर स्टैटिक सिस्टम का उपयोग एप्स स्टैटिक फाइल्स ( STATIC_ROOT) और यूजर अपलोडेड फाइल्स ( MEDIA_ROOT) को स्टोर करने के लिए कर रहा था ।

मुझे अब अमेज़ॅन के एस 3 पर उस सभी सामग्री को होस्ट करने की आवश्यकता है, इसलिए मैंने इसके लिए एक बाल्टी बनाई है। स्टोरेज बैकएंड के django-storagesसाथ उपयोग करते हुए boto, मैं S3 बाल्टी में एकत्रित स्टैटिक्स अपलोड करने में कामयाब रहा:

MEDIA_ROOT = '/media/'
STATIC_ROOT = '/static/'

DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
AWS_ACCESS_KEY_ID = 'KEY_ID...'
AWS_SECRET_ACCESS_KEY = 'ACCESS_KEY...'
AWS_STORAGE_BUCKET_NAME = 'bucket-name'
STATICFILES_STORAGE = 'storages.backends.s3boto.S3BotoStorage'

फिर, मुझे एक समस्या मिली: MEDIA_ROOTऔर STATIC_ROOTबाल्टी के भीतर इसका उपयोग नहीं किया जाता है, इसलिए बाल्टी रूट में स्थिर फ़ाइलें और उपयोगकर्ता अपलोड किए गए पथ दोनों हैं।

तो मैं सेट कर सकता है:

S3_URL = 'http://s3.amazonaws.com/%s' % AWS_STORAGE_BUCKET_NAME
STATIC_URL = S3_URL + STATIC_ROOT
MEDIA_URL = 'S3_URL + MEDIA_ROOT

और टेम्प्लेट में उन सेटिंग्स का उपयोग करें, लेकिन एस 3 में स्टोर करने पर स्थिर / मीडिया फ़ाइलों का कोई भेद नहीं है django-storages

यह कैसे किया जा सकता है?

धन्यवाद!


8
क्योंकि बाल्टी के नाम ( AWS_STORAGE_BUCKET_NAME) को निर्दिष्ट करने के लिए केवल एक ही सेटिंग है , और इसका उपयोग तब किया जाता है जब निर्दिष्ट वर्ग का एक उदाहरण STATICFILES_STORAGEत्वरित किया जाता है।
आर्मंडो पेरेज़ मार्केस

जवाबों:


126

मुझे लगता है कि निम्नलिखित को काम करना चाहिए, और मैंडेक्स की विधि की तुलना में सरल होना चाहिए, हालांकि यह बहुत समान है:

एक s3utils.pyफ़ाइल बनाएँ :

from storages.backends.s3boto import S3BotoStorage

StaticRootS3BotoStorage = lambda: S3BotoStorage(location='static')
MediaRootS3BotoStorage  = lambda: S3BotoStorage(location='media')

फिर अपने में settings.py:

DEFAULT_FILE_STORAGE = 'myproject.s3utils.MediaRootS3BotoStorage'
STATICFILES_STORAGE = 'myproject.s3utils.StaticRootS3BotoStorage'

एक अलग लेकिन संबंधित उदाहरण (जो मैंने वास्तव में परीक्षण किया है) यहां दो example_फाइलों में देखा जा सकता है


1
निश्चित रूप से मेरे संस्करण की तुलना में सरल और बेहतर है। हालाँकि मैंने इसका परीक्षण नहीं किया है, लेकिन मुझे भी लगता है कि यह काम करेगा। धन्यवाद! मैं भी अपने django-s3storage रिपो की जाँच कर रहा हूँ , अगर परियोजना विशेष रूप से S3 का उपयोग करता है तो एक बहुत ही हल्का समाधान लगता है।
आर्मंडो पेरेज़ मार्केज़

1
और, यदि आप पैकेजिंग में अधिक हैं, तो django-s3-folder-storage की जाँच करें । मैंने अभी पाया, यह नहीं बता सकता है कि यह एक ही समाधान है, लेकिन पहले से पैक है।
आर्मंडो पेरेज़ मार्केज़

4
यह मेरे लिए काम नहीं करता है, मीडिया फ़ाइलों को s3 बाल्टी के / पर अपलोड किया जाता है। लगता है कि स्थान सेटिंग का सम्मान नहीं किया जा रहा है। django-storages == 1.1.6, django-extension == 1.1.1, django = 1.4
नाथन कलेर

3
इसके लिए मेरे पास अलग बकेट रखने के लिए अधिक समझ है और मुझे अपनी सेटिंग्स मॉड्यूल के बाहर कॉन्फिग करना पसंद नहीं है, इसलिए मेरा समाधान इस gist.github.com/antonagestam/6075199 की
एनटोनगैस्टम

1
यह समाधान काम नहीं करता है, जो मैं बता सकता हूं। यह दृष्टिकोण होना चाहिए: gist.github.com/defrex/82680e858281d3d3e6e4
19

8

मैं वर्तमान में एक अलग s3utilsमॉड्यूल में इस कोड का उपयोग कर रहा हूं :

from django.core.exceptions import SuspiciousOperation
from django.utils.encoding import force_unicode

from storages.backends.s3boto import S3BotoStorage


def safe_join(base, *paths):
    """
    A version of django.utils._os.safe_join for S3 paths.

    Joins one or more path components to the base path component intelligently.
    Returns a normalized version of the final path.

    The final path must be located inside of the base path component (otherwise
    a ValueError is raised).

    Paths outside the base path indicate a possible security sensitive operation.
    """
    from urlparse import urljoin
    base_path = force_unicode(base)
    paths = map(lambda p: force_unicode(p), paths)
    final_path = urljoin(base_path + ("/" if not base_path.endswith("/") else ""), *paths)
    # Ensure final_path starts with base_path and that the next character after
    # the final path is '/' (or nothing, in which case final_path must be
    # equal to base_path).
    base_path_len = len(base_path) - 1
    if not final_path.startswith(base_path) \
       or final_path[base_path_len:base_path_len + 1] not in ('', '/'):
        raise ValueError('the joined path is located outside of the base path'
                         ' component')
    return final_path


class StaticRootS3BotoStorage(S3BotoStorage):
    def __init__(self, *args, **kwargs):
        super(StaticRootS3BotoStorage, self).__init__(*args, **kwargs)
        self.location = kwargs.get('location', '')
        self.location = 'static/' + self.location.lstrip('/')

    def _normalize_name(self, name):
        try:
            return safe_join(self.location, name).lstrip('/')
        except ValueError:
            raise SuspiciousOperation("Attempted access to '%s' denied." % name)


class MediaRootS3BotoStorage(S3BotoStorage):
    def __init__(self, *args, **kwargs):
        super(MediaRootS3BotoStorage, self).__init__(*args, **kwargs)
        self.location = kwargs.get('location', '')
        self.location = 'media/' + self.location.lstrip('/')

    def _normalize_name(self, name):
        try:
            return safe_join(self.location, name).lstrip('/')
        except ValueError:
            raise SuspiciousOperation("Attempted access to '%s' denied." % name)

फिर, मेरी सेटिंग मॉड्यूल में:

DEFAULT_FILE_STORAGE = 'myproyect.s3utils.MediaRootS3BotoStorage'
STATICFILES_STORAGE = 'myproyect.s3utils.StaticRootS3BotoStorage'

मुझे फ़ंक्शन के _normalize_name()"फिक्स्ड" संस्करण का उपयोग करने के लिए निजी विधि को फिर से परिभाषित करना पड़ा safe_join(), क्योंकि मूल कोड मुझे SuspiciousOperationकानूनी नियमों के लिए अपवाद दे रहा है।

मैं इस पर विचार के लिए पोस्ट कर रहा हूं, अगर कोई बेहतर जवाब दे सकता है या इस में सुधार कर सकता है, तो यह बहुत स्वागत योग्य होगा।


7

फ़ाइल: PROJECT_NAME / custom_storages.py

from django.conf import settings
from storages.backends.s3boto import S3BotoStorage

class StaticStorage(S3BotoStorage):
    location = settings.STATICFILES_LOCATION

class MediaStorage(S3BotoStorage):
    location = settings.MEDIAFILES_LOCATION

फ़ाइल: PROJECT_NAME / settings.py

STATICFILES_LOCATION = 'static'
MEDIAFILES_LOCATION = 'media'

if not DEBUG:
    STATICFILES_STORAGE = 'PROJECT_NAME.custom_storages.StaticStorage'
    DEFAULT_FILE_STORAGE = 'PROJECT_NAME.custom_storages.MediaStorage'
    AWS_ACCESS_KEY_ID = 'KEY_XXXXXXX'
    AWS_SECRET_ACCESS_KEY = 'SECRET_XXXXXXXXX'
    AWS_STORAGE_BUCKET_NAME = 'BUCKET_NAME'
    AWS_HEADERS = {'Cache-Control': 'max-age=86400',}
    AWS_QUERYSTRING_AUTH = False

और भाग खड़ा हुआ: python manage.py collectstatic


यदि आप इस फ़ाइल को नाम देने की storages.pyबजाय करते हैं तो custom_storages.pyआप उपयोग करना चाहते हैंfrom __future__ import absolute_import
हारून मैकमिलिन

2

मुझे लगता है कि उत्तर बहुत सरल है और डिफ़ॉल्ट रूप से किया जाता है। यह मेरे लिए AWS इलास्टिक बीनस्टॉक पर Django 1.6.5 और Boto 2.28.0 के साथ काम कर रहा है।

STATICFILES_FINDERS = (
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
)

TEMPLATE_LOADERS = (
    'django.template.loaders.filesystem.Loader',
    'django.template.loaders.app_directories.Loader',
)

DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
STATICFILES_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
AWS_ACCESS_KEY_ID = os.environ['AWS_ACCESS_KEY_ID']
AWS_SECRET_ACCESS_KEY = os.environ['AWS_SECRET_KEY']

AWS कुंजी कंटेनर कॉन्फिगर फ़ाइल से पास की गई है और मेरे पास बिल्कुल भी नहीं है STATIC_ROOTया STATIC_URLसेट नहीं है । इसके अलावा, s3utils.pyफ़ाइल के लिए कोई ज़रूरत नहीं है । ये विवरण स्वचालित रूप से भंडारण प्रणाली द्वारा नियंत्रित किए जाते हैं। यहाँ चाल यह है कि मुझे अपने टेम्पलेट्स में इस अज्ञात पथ को सही और गतिशील रूप से संदर्भित करने की आवश्यकता है। उदाहरण के लिए:

<link rel="icon" href="{% static "img/favicon.ico" %}">

इस तरह मैं अपने फ़ेविकॉन को संबोधित करता हूं जो स्थानीय रूप से (पूर्व तैनाती) में रहता है ~/Projects/my_app/project/my_app/static/img/favicon.ico

बेशक मेरे पास local_settings.pyदेव माहौल में स्थानीय रूप से इस सामान तक पहुंचने के लिए एक अलग फाइल है और इसमें स्टेटिक और मीडिया सेटिंग्स हैं। मुझे इस समाधान को खोजने के लिए बहुत सारे प्रयोग और पठन करने पड़े और यह बिना किसी त्रुटि के लगातार काम करता है।

मैं समझता हूं कि आपको स्थैतिक और रूट पृथक्करण की आवश्यकता है और यह देखते हुए कि आप केवल एक बाल्टी प्रदान कर सकते हैं, मैं यह बताना चाहूंगा कि यह विधि मेरे स्थानीय वातावरण में सभी फ़ोल्डरों को नीचे ले जाती है ~/Projects/my_app/project/my_app/static/और बाल्टी रूट में एक फ़ोल्डर बनाती है (यानी: S3bucket / img / जैसा कि ऊपर के उदाहरण में है)। तो आप फ़ाइलों का पृथक्करण प्राप्त करते हैं। उदाहरण के लिए, आपके पास mediaफ़ोल्डर में एक फ़ोल्डर हो सकता है staticऔर इसे इसके साथ templating के माध्यम से एक्सेस कर सकता है :

{% static "media/" %}

आशा है कि ये आपकी मदद करेगा। मैं यहां उत्तर की तलाश में आया था और भंडारण प्रणाली का विस्तार करने की तुलना में सरल समाधान खोजने के लिए थोड़ा कठिन धक्का दिया। इसके बजाय, मैंने बोटो के उपयोग के बारे में प्रलेखन पढ़ा और मैंने पाया कि मुझे जो कुछ भी चाहिए वह बहुत कुछ डिफ़ॉल्ट रूप से बनाया गया था। चीयर्स!


0

यदि आप मीडिया या स्थैतिक पृथक्करण से पहले भी सबफ़ोल्डर रखना चाहते हैं, तो आप ब्रैडसेन उत्तर के शीर्ष पर AWS_LOCATION का उपयोग कर सकते हैं। संदर्भ: https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#usage

AWS_STORAGE_BUCKET_NAME = 'bucket_name'
AWS_LOCATION = 'path1/path2/'
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.