Opened 11 years ago
Closed 11 years ago
#22999 closed Bug (invalid)
Impossible to generate migration for model with dynamic upload_to field
| Reported by: | Owned by: | nobody | |
|---|---|---|---|
| Component: | Migrations | Version: | 1.7-rc-1 |
| 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
In my application I have a model which uploads forms to a specific user directory for better file system organization:
media_root/<username>/reports/file
To accomplish this, I use the following model:
upload_dir = upload_to_student_dir('committee/reports/')
class CommitteeReport(TimeStampedModel):
user = models.ForeignKey(User)
document = models.FileField(upload_to=upload_dir)
The function defines and returns an inner function which will provide the complete path based on the instance's user:
def upload_to_student_dir(sub_path=''):
def callable(instance, filename):
"""Dynamically returns the user directory to which this file should be uploaded.
"""
path = "students/{0}/{1}{2}".format(instance.user.username, sub_path, filename)
return path
return callable
Creating a migration via South seemed to have caused no problems, yet the analysis being employed by django.db.migrations differs and generates the following error:
Migrations for 'committee':
0001_initial.py:
- Create model CommitteeReport
Traceback (most recent call last):
File "manage.py", line 11, in <module>
execute_from_command_line(sys.argv)
File "/home/kevin/.virtualenvs/stageportfolio/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 385, in execute_from_command_line
utility.execute()
File "/home/kevin/.virtualenvs/stageportfolio/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 377, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/home/kevin/.virtualenvs/stageportfolio/local/lib/python2.7/site-packages/django/core/management/base.py", line 288, in run_from_argv
self.execute(*args, **options.__dict__)
File "/home/kevin/.virtualenvs/stageportfolio/local/lib/python2.7/site-packages/django/core/management/base.py", line 337, in execute
output = self.handle(*args, **options)
File "/home/kevin/.virtualenvs/stageportfolio/local/lib/python2.7/site-packages/django/core/management/commands/makemigrations.py", line 115, in handle
self.write_migration_files(changes)
File "/home/kevin/.virtualenvs/stageportfolio/local/lib/python2.7/site-packages/django/core/management/commands/makemigrations.py", line 143, in write_migration_files
migration_string = writer.as_string()
File "/home/kevin/.virtualenvs/stageportfolio/local/lib/python2.7/site-packages/django/db/migrations/writer.py", line 124, in as_string
operation_string, operation_imports = OperationWriter(operation).serialize()
File "/home/kevin/.virtualenvs/stageportfolio/local/lib/python2.7/site-packages/django/db/migrations/writer.py", line 76, in serialize
arg_string, arg_imports = MigrationWriter.serialize(item)
File "/home/kevin/.virtualenvs/stageportfolio/local/lib/python2.7/site-packages/django/db/migrations/writer.py", line 229, in serialize
item_string, item_imports = cls.serialize(item)
File "/home/kevin/.virtualenvs/stageportfolio/local/lib/python2.7/site-packages/django/db/migrations/writer.py", line 290, in serialize
return cls.serialize_deconstructed(path, args, kwargs)
File "/home/kevin/.virtualenvs/stageportfolio/local/lib/python2.7/site-packages/django/db/migrations/writer.py", line 205, in serialize_deconstructed
arg_string, arg_imports = cls.serialize(arg)
File "/home/kevin/.virtualenvs/stageportfolio/local/lib/python2.7/site-packages/django/db/migrations/writer.py", line 316, in serialize
"Could not find function %s in %s.\nPlease note that "
ValueError: Could not find function %s in %s.
Please note that due to Python 2 limitations, you cannot serialize unbound method functions (e.g. a method declared
and used in the same class body). Please move the function into the main module body to use migrations.
For more information, see https://docs.djangoproject.com/en/1.7/topics/migrations/#serializing-values
As you can see I have already moved the function into the main module, yet the error persists.
What you've done is moving the function factory to the main module, as described by the exception message there's no way Django can reconstruct the returned inner function.
I suggest you define a callable factory class that implements
deconstructinstead:This use to work with South because it didn't serialize the
upload_tooption of theFileFieldand it subclasses.I'll mark as invalid since this is a well known limitation of the migration framework.