For example, given a model definition:
{{{
from django.core.files.storage import FileSystemStorage, default_storage
from django.db import models
import random
other_storage = FileSystemStorage(location='/media/other')
def get_storage():
return random.choice([default_storage, other_storage])
class MyModel(models.Model):
my_file = models.FileField(storage=get_storage)
}}}
repeatedly running `makemigrations` will randomly generate a migration
that alternately includes or omits `storage=myapp.models.get_storage` on
the FileField definition.
This case was overlooked in the fix for #31941 - the deconstruct method
tests `if self.storage is not default_storage` to determine whether to add
the `storage` kwarg, but at this point `self.storage` is the evaluated
version, so it wrongly returns false for a callable that returns
`default_storage`.
--
Ticket URL: <https://code.djangoproject.com/ticket/34192>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
* stage: Unreviewed => Accepted
Comment:
Yes, OK. That looks correct. We're essentially saying that when
`hasattr(self, "_storage_callable")` that should unconditionally be used
by `deconstruct`. 🤔
--
Ticket URL: <https://code.djangoproject.com/ticket/34192#comment:1>
* component: Migrations => Database layer (models, ORM)
Comment:
We should probably use `getattr(self, "_storage_callable", self.storage)`
in both lines.
--
Ticket URL: <https://code.djangoproject.com/ticket/34192#comment:2>
* owner: nobody => Francesco Panico
* status: new => assigned
--
Ticket URL: <https://code.djangoproject.com/ticket/34192#comment:3>
* owner: Francesco Panico => (none)
--
Ticket URL: <https://code.djangoproject.com/ticket/34192#comment:4>
* owner: (none) => Abhinav Yadav
--
Ticket URL: <https://code.djangoproject.com/ticket/34192#comment:5>
* owner: Abhinav Yadav => Matt Westcott
--
Ticket URL: <https://code.djangoproject.com/ticket/34192#comment:6>
* has_patch: 0 => 1
Comment:
PR: https://github.com/django/django/pull/16493
--
Ticket URL: <https://code.djangoproject.com/ticket/34192#comment:7>
* stage: Accepted => Ready for checkin
--
Ticket URL: <https://code.djangoproject.com/ticket/34192#comment:8>
* status: assigned => closed
* resolution: => fixed
Comment:
In [changeset:"ef85b6bf0bc5a8b194f0724cf5bbedbcee402b96" ef85b6b]:
{{{
#!CommitTicketReference repository=""
revision="ef85b6bf0bc5a8b194f0724cf5bbedbcee402b96"
Fixed #34192 -- Preserved callable storage when it returns
default_storage.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/34192#comment:9>
Comment (by Mariusz Felisiak <felisiak.mariusz@…>):
In [changeset:"b332a96cd721defb6ff13ba1bc57958a984f0773" b332a96]:
{{{
#!CommitTicketReference repository=""
revision="b332a96cd721defb6ff13ba1bc57958a984f0773"
[4.2.x] Fixed #34192 -- Preserved callable storage when it returns
default_storage.
Backport of ef85b6bf0bc5a8b194f0724cf5bbedbcee402b96 from main
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/34192#comment:10>