Opened 38 hours ago

Closed 36 hours ago

#36824 closed New feature (wontfix)

FileField storage parameter should support string references to STORAGES dict keys

Reported by: Petr Dlouhý Owned by:
Component: File uploads/storage Version: 6.0
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Summary

FileField's storage parameter doesn't support string references to STORAGES dict keys, despite Django 4.2+ establishing STORAGES as the standard configuration method. This creates confusion and forces workarounds.

Description

Django 4.2 introduced the STORAGES setting as a centralized dictionary for configuring storage backends, deprecating DEFAULT_FILE_STORAGE. However, FileField and ImageField don't support string references to these storage keys.

Current Behavior

# settings.py
STORAGES = {
    "default": {...},
    "private_assets": {...},
}

# models.py
from django.core.files.storage import storages

# This works - but verbose and requires callable wrapper
def get_private_storage():
    return storages["private_assets"]

class MyModel(models.Model):
    file = models.FileField(storage=get_private_storage)

Expected Behavior

# This should work - consistent with STORAGES design
class MyModel(models.Model):
    file = models.FileField(storage="private_assets")

Problem

When developers try the intuitive approach (storage="private_assets"), Django stores it as a string. This fails silently until runtime when code accesses field.storage, causing:

AttributeError: 'str' object has no attribute 'path'

This is particularly problematic for third-party libraries (like easy-thumbnails) that access field.storage directly and expect a storage object, not a string.

Inconsistency

The STORAGES dict uses string keys everywhere:

  • settings.STORAGES["default"] - configuration
  • storages["private_assets"] - runtime access
  • THUMBNAIL_DEFAULT_STORAGE = "thumbnails" - library settings
  • FileField(storage="name") - doesn't work

This breaks the principle of least surprise. If Django establishes a pattern (string keys for storage), it should work consistently across the framework.

Real-World Impact

I encountered this while implementing Django STORAGES support for easy-thumbnails. Users naturally try storage="name" based on the STORAGES pattern, and it fails with a cryptic error. This forced me to add defensive string resolution in the library.

Proposed Solutions

Option A: Support string storage in FileField (Recommended)

Add string resolution in FileField.__init__():

def __init__(self, ..., storage=None, **kwargs):
    self.storage = storage or default_storage
    
    # Resolve string references to STORAGES dict
    if isinstance(self.storage, str):
        from django.core.files.storage import storages
        self.storage = storages[self.storage]
    
    if callable(self.storage):
        self._storage_callable = self.storage
        self.storage = self.storage()
        ...

Benefits:

  • Consistent with STORAGES design
  • Intuitive for developers
  • Backwards compatible (no breaking changes)
  • ~5 lines of code

Option B: Document that string storage is not supported

If supporting string storage is not desired, clearly document in FileField docs:

Note: The storage parameter does not support string references to STORAGES dict keys. 
Use a callable function to reference configured storages:

def get_my_storage():
    from django.core.files.storage import storages
    return storages["my_storage"]

file = models.FileField(storage=get_my_storage)

This at least prevents confusion and provides a clear workaround.

Migration Behavior

String storage resolution wouldn't create migration issues because:

  • Strings would be resolved at model load time (like callables)
  • Migrations would store the string reference, not the resolved object
  • This mirrors how callable storage already works

Backwards Compatibility

Fully backwards compatible - existing code using storage objects or callables continues working unchanged.

Related Tickets

  • #31941 - FileField with callable storage deconstruction
  • #34192 - Callable storage returning default_storage

Questions

  1. Was excluding string storage from FileField intentional, or an oversight during STORAGES implementation?
  2. If intentional, what's the reasoning? (I'd like to understand the design decision)
  3. If not desired as a feature, can we at least improve documentation to prevent this confusion?

Change History (1)

in reply to:  description comment:1 by Natalia Bidart, 36 hours ago

Component: UncategorizedFile uploads/storage
Resolution: wontfix
Status: newclosed

Replying to Petr Dlouhý:

Hello Petr! The storage option works exactly as described in the docs:

A storage object, or a callable which returns a storage object.

When suggesting a new feature for Django, the feature should first be proposed and discussed with the community. To do that, please raise this on the new feature tracker where you'll receive feedback from the community.

I'll close the ticket for now, but if the community agrees with the proposal, please return to this ticket and reference the feature discussion so we can re-open it. For more information, please refer to the documented guidelines for requesting features.

Lastly, please avoid using LLM to generate overly verbose reports.

Note: See TracTickets for help on using tickets.
Back to Top