mirror of
https://github.com/django/django.git
synced 2025-02-11 09:55:22 +00:00
Moved the lookup in Field.swappable_setting to Apps, and added an lru_cache to cache the results. Refs #24743 Thanks Marten Kenbeek for the initial work on the patch. Thanks Aymeric Augustin and Tim Graham for the review.
395 lines
18 KiB
Python
395 lines
18 KiB
Python
from __future__ import unicode_literals
|
|
|
|
from django.apps import apps
|
|
from django.db import models
|
|
from django.test import SimpleTestCase, override_settings
|
|
from django.test.utils import isolate_lru_cache
|
|
from django.utils import six
|
|
|
|
|
|
class FieldDeconstructionTests(SimpleTestCase):
|
|
"""
|
|
Tests the deconstruct() method on all core fields.
|
|
"""
|
|
|
|
def test_name(self):
|
|
"""
|
|
Tests the outputting of the correct name if assigned one.
|
|
"""
|
|
# First try using a "normal" field
|
|
field = models.CharField(max_length=65)
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertIsNone(name)
|
|
field.set_attributes_from_name("is_awesome_test")
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(name, "is_awesome_test")
|
|
self.assertIsInstance(name, six.text_type)
|
|
# Now try with a ForeignKey
|
|
field = models.ForeignKey("some_fake.ModelName", models.CASCADE)
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertIsNone(name)
|
|
field.set_attributes_from_name("author")
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(name, "author")
|
|
|
|
def test_auto_field(self):
|
|
field = models.AutoField(primary_key=True)
|
|
field.set_attributes_from_name("id")
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.AutoField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {"primary_key": True})
|
|
|
|
def test_big_integer_field(self):
|
|
field = models.BigIntegerField()
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.BigIntegerField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {})
|
|
|
|
def test_boolean_field(self):
|
|
field = models.BooleanField()
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.BooleanField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {})
|
|
field = models.BooleanField(default=True)
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.BooleanField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {"default": True})
|
|
|
|
def test_char_field(self):
|
|
field = models.CharField(max_length=65)
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.CharField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {"max_length": 65})
|
|
field = models.CharField(max_length=65, null=True, blank=True)
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.CharField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {"max_length": 65, "null": True, "blank": True})
|
|
|
|
def test_char_field_choices(self):
|
|
field = models.CharField(max_length=1, choices=(("A", "One"), ("B", "Two")))
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.CharField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {"choices": [("A", "One"), ("B", "Two")], "max_length": 1})
|
|
|
|
def test_csi_field(self):
|
|
field = models.CommaSeparatedIntegerField(max_length=100)
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.CommaSeparatedIntegerField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {"max_length": 100})
|
|
|
|
def test_date_field(self):
|
|
field = models.DateField()
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.DateField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {})
|
|
field = models.DateField(auto_now=True)
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.DateField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {"auto_now": True})
|
|
|
|
def test_datetime_field(self):
|
|
field = models.DateTimeField()
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.DateTimeField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {})
|
|
field = models.DateTimeField(auto_now_add=True)
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.DateTimeField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {"auto_now_add": True})
|
|
# Bug #21785
|
|
field = models.DateTimeField(auto_now=True, auto_now_add=True)
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.DateTimeField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {"auto_now_add": True, "auto_now": True})
|
|
|
|
def test_decimal_field(self):
|
|
field = models.DecimalField(max_digits=5, decimal_places=2)
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.DecimalField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {"max_digits": 5, "decimal_places": 2})
|
|
|
|
def test_decimal_field_0_decimal_places(self):
|
|
"""
|
|
A DecimalField with decimal_places=0 should work (#22272).
|
|
"""
|
|
field = models.DecimalField(max_digits=5, decimal_places=0)
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.DecimalField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {"max_digits": 5, "decimal_places": 0})
|
|
|
|
def test_email_field(self):
|
|
field = models.EmailField()
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.EmailField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {"max_length": 254})
|
|
field = models.EmailField(max_length=255)
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.EmailField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {"max_length": 255})
|
|
|
|
def test_file_field(self):
|
|
field = models.FileField(upload_to="foo/bar")
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.FileField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {"upload_to": "foo/bar"})
|
|
# Test max_length
|
|
field = models.FileField(upload_to="foo/bar", max_length=200)
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.FileField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {"upload_to": "foo/bar", "max_length": 200})
|
|
|
|
def test_file_path_field(self):
|
|
field = models.FilePathField(match=".*\.txt$")
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.FilePathField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {"match": ".*\.txt$"})
|
|
field = models.FilePathField(recursive=True, allow_folders=True, max_length=123)
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.FilePathField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {"recursive": True, "allow_folders": True, "max_length": 123})
|
|
|
|
def test_float_field(self):
|
|
field = models.FloatField()
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.FloatField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {})
|
|
|
|
def test_foreign_key(self):
|
|
# Test basic pointing
|
|
from django.contrib.auth.models import Permission
|
|
field = models.ForeignKey("auth.Permission", models.CASCADE)
|
|
field.remote_field.model = Permission
|
|
field.remote_field.field_name = "id"
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.ForeignKey")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {"to": "auth.Permission", "on_delete": models.CASCADE})
|
|
self.assertFalse(hasattr(kwargs['to'], "setting_name"))
|
|
# Test swap detection for swappable model
|
|
field = models.ForeignKey("auth.User", models.CASCADE)
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.ForeignKey")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {"to": "auth.User", "on_delete": models.CASCADE})
|
|
self.assertEqual(kwargs['to'].setting_name, "AUTH_USER_MODEL")
|
|
# Test nonexistent (for now) model
|
|
field = models.ForeignKey("something.Else", models.CASCADE)
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.ForeignKey")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {"to": "something.Else", "on_delete": models.CASCADE})
|
|
# Test on_delete
|
|
field = models.ForeignKey("auth.User", models.SET_NULL)
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.ForeignKey")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {"to": "auth.User", "on_delete": models.SET_NULL})
|
|
# Test to_field preservation
|
|
field = models.ForeignKey("auth.Permission", models.CASCADE, to_field="foobar")
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.ForeignKey")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {"to": "auth.Permission", "to_field": "foobar", "on_delete": models.CASCADE})
|
|
# Test related_name preservation
|
|
field = models.ForeignKey("auth.Permission", models.CASCADE, related_name="foobar")
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.ForeignKey")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {"to": "auth.Permission", "related_name": "foobar", "on_delete": models.CASCADE})
|
|
|
|
@override_settings(AUTH_USER_MODEL="auth.Permission")
|
|
def test_foreign_key_swapped(self):
|
|
with isolate_lru_cache(apps.get_swappable_settings_name):
|
|
# It doesn't matter that we swapped out user for permission;
|
|
# there's no validation. We just want to check the setting stuff works.
|
|
field = models.ForeignKey("auth.Permission", models.CASCADE)
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.ForeignKey")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {"to": "auth.Permission", "on_delete": models.CASCADE})
|
|
self.assertEqual(kwargs['to'].setting_name, "AUTH_USER_MODEL")
|
|
|
|
def test_image_field(self):
|
|
field = models.ImageField(upload_to="foo/barness", width_field="width", height_field="height")
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.ImageField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {"upload_to": "foo/barness", "width_field": "width", "height_field": "height"})
|
|
|
|
def test_integer_field(self):
|
|
field = models.IntegerField()
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.IntegerField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {})
|
|
|
|
def test_ip_address_field(self):
|
|
field = models.IPAddressField()
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.IPAddressField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {})
|
|
|
|
def test_generic_ip_address_field(self):
|
|
field = models.GenericIPAddressField()
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.GenericIPAddressField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {})
|
|
field = models.GenericIPAddressField(protocol="IPv6")
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.GenericIPAddressField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {"protocol": "IPv6"})
|
|
|
|
def test_many_to_many_field(self):
|
|
# Test normal
|
|
field = models.ManyToManyField("auth.Permission")
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.ManyToManyField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {"to": "auth.Permission"})
|
|
self.assertFalse(hasattr(kwargs['to'], "setting_name"))
|
|
# Test swappable
|
|
field = models.ManyToManyField("auth.User")
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.ManyToManyField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {"to": "auth.User"})
|
|
self.assertEqual(kwargs['to'].setting_name, "AUTH_USER_MODEL")
|
|
# Test through
|
|
field = models.ManyToManyField("auth.Permission", through="auth.Group")
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.ManyToManyField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {"to": "auth.Permission", "through": "auth.Group"})
|
|
# Test custom db_table
|
|
field = models.ManyToManyField("auth.Permission", db_table="custom_table")
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.ManyToManyField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {"to": "auth.Permission", "db_table": "custom_table"})
|
|
# Test related_name
|
|
field = models.ManyToManyField("auth.Permission", related_name="custom_table")
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.ManyToManyField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {"to": "auth.Permission", "related_name": "custom_table"})
|
|
|
|
@override_settings(AUTH_USER_MODEL="auth.Permission")
|
|
def test_many_to_many_field_swapped(self):
|
|
with isolate_lru_cache(apps.get_swappable_settings_name):
|
|
# It doesn't matter that we swapped out user for permission;
|
|
# there's no validation. We just want to check the setting stuff works.
|
|
field = models.ManyToManyField("auth.Permission")
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.ManyToManyField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {"to": "auth.Permission"})
|
|
self.assertEqual(kwargs['to'].setting_name, "AUTH_USER_MODEL")
|
|
|
|
def test_null_boolean_field(self):
|
|
field = models.NullBooleanField()
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.NullBooleanField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {})
|
|
|
|
def test_positive_integer_field(self):
|
|
field = models.PositiveIntegerField()
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.PositiveIntegerField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {})
|
|
|
|
def test_positive_small_integer_field(self):
|
|
field = models.PositiveSmallIntegerField()
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.PositiveSmallIntegerField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {})
|
|
|
|
def test_slug_field(self):
|
|
field = models.SlugField()
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.SlugField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {})
|
|
field = models.SlugField(db_index=False, max_length=231)
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.SlugField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {"db_index": False, "max_length": 231})
|
|
|
|
def test_small_integer_field(self):
|
|
field = models.SmallIntegerField()
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.SmallIntegerField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {})
|
|
|
|
def test_text_field(self):
|
|
field = models.TextField()
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.TextField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {})
|
|
|
|
def test_time_field(self):
|
|
field = models.TimeField()
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.TimeField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {})
|
|
|
|
field = models.TimeField(auto_now=True)
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {'auto_now': True})
|
|
|
|
field = models.TimeField(auto_now_add=True)
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {'auto_now_add': True})
|
|
|
|
def test_url_field(self):
|
|
field = models.URLField()
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.URLField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {})
|
|
field = models.URLField(max_length=231)
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.URLField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {"max_length": 231})
|
|
|
|
def test_binary_field(self):
|
|
field = models.BinaryField()
|
|
name, path, args, kwargs = field.deconstruct()
|
|
self.assertEqual(path, "django.db.models.BinaryField")
|
|
self.assertEqual(args, [])
|
|
self.assertEqual(kwargs, {})
|