0

I have created a custom utility function for Django FileField's upload_to parameter. This function accepts a prefix and returns a function that actually accepts instance and filename. But when I run manage.py makemigrations, the command throws ValueError. I have included the related files/data below.

secret_upload function

import uuid

def secret_upload(prefix):
    def _path(instance, filename):
        file = filename.split(".")
        fuuid = uuid.uuid4()

        if len(file) == 1:
            filename = f"secrets/{prefix}/{file[0]}-{fuuid}"
        elif len(file) == 2:
            filename = f"secrets/{prefix}/{file[0]}-{fuuid}.{file[1]}"

        return filename

    return _path

Django Model

class SecretData(models.Model):
    name = models.CharField(max_length=100)
    secret_file = models.FileField(upload_to=secret_upload("files"))

makemigrations error traceback

 (most recent call last):
  File "D:\Python\projects\keep-creds\keep_creds\manage.py", line 22, in <module>
    main()
  File "D:\Python\projects\keep-creds\keep_creds\manage.py", line 18, in main
    execute_from_command_line(sys.argv)
  File "D:\Python\projects\kc-venv\lib\site-packages\django\core\management\__init__.py", line 425, in execute_from_command_line
    utility.execute()
  File "D:\Python\projects\kc-venv\lib\site-packages\django\core\management\__init__.py", line 419, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "D:\Python\projects\kc-venv\lib\site-packages\django\core\management\base.py", line 373, in run_from_argv
    self.execute(*args, **cmd_options)
  File "D:\Python\projects\kc-venv\lib\site-packages\django\core\management\base.py", line 417, in execute
    output = self.handle(*args, **options)
  File "D:\Python\projects\kc-venv\lib\site-packages\django\core\management\base.py", line 90, in wrapped
    res = handle_func(*args, **kwargs)
  File "D:\Python\projects\kc-venv\lib\site-packages\django\core\management\commands\makemigrations.py", line 190, in handle
    self.write_migration_files(changes)
  File "D:\Python\projects\kc-venv\lib\site-packages\django\core\management\commands\makemigrations.py", line 227, in write_migration_files
    migration_string = writer.as_string()
  File "D:\Python\projects\kc-venv\lib\site-packages\django\db\migrations\writer.py", line 141, in as_string
    operation_string, operation_imports = OperationWriter(operation).serialize()
  File "D:\Python\projects\kc-venv\lib\site-packages\django\db\migrations\writer.py", line 99, in serialize
    _write(arg_name, arg_value)
  File "D:\Python\projects\kc-venv\lib\site-packages\django\db\migrations\writer.py", line 63, in _write
    arg_string, arg_imports = MigrationWriter.serialize(_arg_value)
  File "D:\Python\projects\kc-venv\lib\site-packages\django\db\migrations\writer.py", line 271, in serialize
    return serializer_factory(value).serialize()
  File "D:\Python\projects\kc-venv\lib\site-packages\django\db\migrations\serializer.py", line 201, in serialize
    return self.serialize_deconstructed(path, args, kwargs)
  File "D:\Python\projects\kc-venv\lib\site-packages\django\db\migrations\serializer.py", line 88, in serialize_deconstructed
    arg_string, arg_imports = serializer_factory(arg).serialize()
  File "D:\Python\projects\kc-venv\lib\site-packages\django\db\migrations\serializer.py", line 160, in serialize
    raise ValueError(
ValueError: Could not find function _path in credentials.utils.

What could be the possible reason behind this? Because the _path is defined inside.

Atharva Kale
  • 59
  • 1
  • 9

1 Answers1

1

The problem occurs when Django tries to serialize your Model for the purpose of creating the migration file.

If you look inside django/db/migrations/serializer.py you'll see the following:

    if '<' not in self.value.__qualname__:  # Qualname can include <locals>
        return '%s.%s' % (module_name, self.value.__qualname__), {'import %s' % self.value.__module__}
    
    raise ValueError(
        'Could not find function %s in %s.\n' % (self.value.__name__, module_name)
    )

Meaning that local functions cannot be used.

Ari
  • 21
  • 4
  • Any bypass to this? The function work just fine. Only makemigrations is giving issues. – Atharva Kale Jan 21 '22 at 18:59
  • 1
    Perhaps this will be bad advise, but if your function is intended to be used only during actual runtime (and not during migrations) then you could try temporarily changing the contents of your `secret_upload` function to return some global function while you run `makemigrations`, and restore it after the migration is created (or some other similar trick). This way you would "trick" Django into believing this migration is done. – Ari Jan 23 '22 at 07:19
  • Makes sense, @Ari. But whenever I make any migrations, I will have to comment the given function and proceed, right? – Atharva Kale Jan 23 '22 at 08:02
  • I'm not sure, I don't know enough about the internals of the migrations mechanism to predict that with certainty. However, I would hope that as long as the definition of your class keeps pointing to the same function in exactly the same manner, then Django will not detect modifications that require another migration. Give it a try, you'll have your answer right away (let us know :) ) – Ari Jan 23 '22 at 10:05