ValueError:在 Django 4.0 中调用 makemigrations 时找不到函数验证器

bay*_*man 2 django

使用此处的解决方案来验证 URLField,我在运行时收到 ValueError python manage.py makemigrations,但我不确定为什么。我究竟做错了什么?

from django.contrib.auth.models import User
from django.db import models
from django.core.exceptions import ValidationError

from urllib.parse import urlparse


def validate_hostname(*hostnames):
    hostnames = set(hostnames)
    def validator(value):
        try:
            result = urlparse(value)
            if result.hostname not in hostnames:
                raise ValidationError(f'The hostname {result.hostname} is not allowed.')
        except ValueError:
            raise ValidationError('Invalid URL')
    return validator

class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.SET_NULL, null=True)
    twitter = models.URLField(
        blank=True,
        null=True,
        validators=[validate_hostname('twitter.com', 'www.twitter.com')]
    )
Run Code Online (Sandbox Code Playgroud)

追溯

$ python manage.py makemigrations

Migrations for 'userprofiles':
  userprofiles/migrations/0002_userprofile_twitter.py
    - Add field twitter to userprofile
Traceback (most recent call last):
  File "/home/master/github/mywebsite/src/manage.py", line 22, in <module>
    main()
  File "/home/master/github/mywebsite/src/manage.py", line 18, in main
    execute_from_command_line(sys.argv)
  File "/home/master/.cache/pypoetry/virtualenvs/mywebsite-WMQVlvmt-py3.10/lib/python3.10/site-packages/django/core/management/__init__.py", line 446, in execute_from_command_line
    utility.execute()
  File "/home/master/.cache/pypoetry/virtualenvs/mywebsite-WMQVlvmt-py3.10/lib/python3.10/site-packages/django/core/management/__init__.py", line 440, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/home/master/.cache/pypoetry/virtualenvs/mywebsite-WMQVlvmt-py3.10/lib/python3.10/site-packages/django/core/management/base.py", line 414, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/home/master/.cache/pypoetry/virtualenvs/mywebsite-WMQVlvmt-py3.10/lib/python3.10/site-packages/django/core/management/base.py", line 460, in execute
    output = self.handle(*args, **options)
  File "/home/master/.cache/pypoetry/virtualenvs/mywebsite-WMQVlvmt-py3.10/lib/python3.10/site-packages/django/core/management/base.py", line 98, in wrapped
    res = handle_func(*args, **kwargs)
  File "/home/master/.cache/pypoetry/virtualenvs/mywebsite-WMQVlvmt-py3.10/lib/python3.10/site-packages/django/core/management/commands/makemigrations.py", line 214, in handle
    self.write_migration_files(changes)
  File "/home/master/.cache/pypoetry/virtualenvs/mywebsite-WMQVlvmt-py3.10/lib/python3.10/site-packages/django/core/management/commands/makemigrations.py", line 255, in write_migration_files
    migration_string = writer.as_string()
  File "/home/master/.cache/pypoetry/virtualenvs/mywebsite-WMQVlvmt-py3.10/lib/python3.10/site-packages/django/db/migrations/writer.py", line 141, in as_string
    operation_string, operation_imports = OperationWriter(operation).serialize()
  File "/home/master/.cache/pypoetry/virtualenvs/mywebsite-WMQVlvmt-py3.10/lib/python3.10/site-packages/django/db/migrations/writer.py", line 99, in serialize
    _write(arg_name, arg_value)
  File "/home/master/.cache/pypoetry/virtualenvs/mywebsite-WMQVlvmt-py3.10/lib/python3.10/site-packages/django/db/migrations/writer.py", line 63, in _write
    arg_string, arg_imports = MigrationWriter.serialize(_arg_value)
  File "/home/master/.cache/pypoetry/virtualenvs/mywebsite-WMQVlvmt-py3.10/lib/python3.10/site-packages/django/db/migrations/writer.py", line 282, in serialize
    return serializer_factory(value).serialize()
  File "/home/master/.cache/pypoetry/virtualenvs/mywebsite-WMQVlvmt-py3.10/lib/python3.10/site-packages/django/db/migrations/serializer.py", line 216, in serialize
    return self.serialize_deconstructed(path, args, kwargs)
  File "/home/master/.cache/pypoetry/virtualenvs/mywebsite-WMQVlvmt-py3.10/lib/python3.10/site-packages/django/db/migrations/serializer.py", line 94, in serialize_deconstructed
    arg_string, arg_imports = serializer_factory(arg).serialize()
  File "/home/master/.cache/pypoetry/virtualenvs/mywebsite-WMQVlvmt-py3.10/lib/python3.10/site-packages/django/db/migrations/serializer.py", line 43, in serialize
    item_string, item_imports = serializer_factory(item).serialize()
  File "/home/master/.cache/pypoetry/virtualenvs/mywebsite-WMQVlvmt-py3.10/lib/python3.10/site-packages/django/db/migrations/serializer.py", line 172, in serialize
    raise ValueError(
ValueError: Could not find function validator in userprofiles.models.
Run Code Online (Sandbox Code Playgroud)

Dom*_*kis 7

这可以通过添加装饰来解决functools.wraps

from functools import wraps
[...]

def validate_hostname(*hostnames):
    [...]
    @wraps(validate_hostname)
    def validator(value):
        [...]
    return validator
Run Code Online (Sandbox Code Playgroud)