mirror of
https://github.com/django/django.git
synced 2024-12-22 09:05:43 +00:00
Ported over Field.deconstruct() from my schema alteration branch.
This is to help other ongoing branches which would benefit from this functionality.
This commit is contained in:
parent
8809da67a2
commit
48dd1e63bb
@ -99,7 +99,8 @@ class Field(object):
|
||||
db_tablespace=None, auto_created=False, validators=[],
|
||||
error_messages=None):
|
||||
self.name = name
|
||||
self.verbose_name = verbose_name
|
||||
self.verbose_name = verbose_name # May be set by set_attributes_from_name
|
||||
self._verbose_name = verbose_name # Store original for deconstruction
|
||||
self.primary_key = primary_key
|
||||
self.max_length, self._unique = max_length, unique
|
||||
self.blank, self.null = blank, null
|
||||
@ -128,14 +129,99 @@ class Field(object):
|
||||
self.creation_counter = Field.creation_counter
|
||||
Field.creation_counter += 1
|
||||
|
||||
self._validators = validators # Store for deconstruction later
|
||||
self.validators = self.default_validators + validators
|
||||
|
||||
messages = {}
|
||||
for c in reversed(self.__class__.__mro__):
|
||||
messages.update(getattr(c, 'default_error_messages', {}))
|
||||
messages.update(error_messages or {})
|
||||
self._error_messages = error_messages # Store for deconstruction later
|
||||
self.error_messages = messages
|
||||
|
||||
def deconstruct(self):
|
||||
"""
|
||||
Returns enough information to recreate the field as a 4-tuple:
|
||||
|
||||
* The name of the field on the model, if contribute_to_class has been run
|
||||
* The import path of the field, including the class: django.db.models.IntegerField
|
||||
This should be the most portable version, so less specific may be better.
|
||||
* A list of positional arguments
|
||||
* A dict of keyword arguments
|
||||
|
||||
Note that the positional or keyword arguments must contain values of the
|
||||
following types (including inner values of collection types):
|
||||
|
||||
* None, bool, str, unicode, int, long, float, complex, set, frozenset, list, tuple, dict
|
||||
* UUID
|
||||
* datetime.datetime (naive), datetime.date
|
||||
* top-level classes, top-level functions - will be referenced by their full import path
|
||||
* Storage instances - these have their own deconstruct() method
|
||||
|
||||
This is because the values here must be serialised into a text format
|
||||
(possibly new Python code, possibly JSON) and these are the only types
|
||||
with encoding handlers defined.
|
||||
|
||||
There's no need to return the exact way the field was instantiated this time,
|
||||
just ensure that the resulting field is the same - prefer keyword arguments
|
||||
over positional ones, and omit parameters with their default values.
|
||||
"""
|
||||
# Short-form way of fetching all the default parameters
|
||||
keywords = {}
|
||||
possibles = {
|
||||
"verbose_name": None,
|
||||
"primary_key": False,
|
||||
"max_length": None,
|
||||
"unique": False,
|
||||
"blank": False,
|
||||
"null": False,
|
||||
"db_index": False,
|
||||
"default": NOT_PROVIDED,
|
||||
"editable": True,
|
||||
"serialize": True,
|
||||
"unique_for_date": None,
|
||||
"unique_for_month": None,
|
||||
"unique_for_year": None,
|
||||
"choices": [],
|
||||
"help_text": '',
|
||||
"db_column": None,
|
||||
"db_tablespace": settings.DEFAULT_INDEX_TABLESPACE,
|
||||
"auto_created": False,
|
||||
"validators": [],
|
||||
"error_messages": None,
|
||||
}
|
||||
attr_overrides = {
|
||||
"unique": "_unique",
|
||||
"choices": "_choices",
|
||||
"error_messages": "_error_messages",
|
||||
"validators": "_validators",
|
||||
"verbose_name": "_verbose_name",
|
||||
}
|
||||
equals_comparison = set(["choices", "validators", "db_tablespace"])
|
||||
for name, default in possibles.items():
|
||||
value = getattr(self, attr_overrides.get(name, name))
|
||||
if name in equals_comparison:
|
||||
if value != default:
|
||||
keywords[name] = value
|
||||
else:
|
||||
if value is not default:
|
||||
keywords[name] = value
|
||||
# Work out path - we shorten it for known Django core fields
|
||||
path = "%s.%s" % (self.__class__.__module__, self.__class__.__name__)
|
||||
if path.startswith("django.db.models.fields.related"):
|
||||
path = path.replace("django.db.models.fields.related", "django.db.models")
|
||||
if path.startswith("django.db.models.fields.files"):
|
||||
path = path.replace("django.db.models.fields.files", "django.db.models")
|
||||
if path.startswith("django.db.models.fields"):
|
||||
path = path.replace("django.db.models.fields", "django.db.models")
|
||||
# Return basic info - other fields should override this.
|
||||
return (
|
||||
self.name,
|
||||
path,
|
||||
[],
|
||||
keywords,
|
||||
)
|
||||
|
||||
def __eq__(self, other):
|
||||
# Needed for @total_ordering
|
||||
if isinstance(other, Field):
|
||||
@ -566,6 +652,7 @@ class Field(object):
|
||||
return '<%s: %s>' % (path, name)
|
||||
return '<%s>' % path
|
||||
|
||||
|
||||
class AutoField(Field):
|
||||
description = _("Integer")
|
||||
|
||||
@ -580,6 +667,12 @@ class AutoField(Field):
|
||||
kwargs['blank'] = True
|
||||
Field.__init__(self, *args, **kwargs)
|
||||
|
||||
def deconstruct(self):
|
||||
name, path, args, kwargs = super(AutoField, self).deconstruct()
|
||||
del kwargs['blank']
|
||||
kwargs['primary_key'] = True
|
||||
return name, path, args, kwargs
|
||||
|
||||
def get_internal_type(self):
|
||||
return "AutoField"
|
||||
|
||||
@ -630,6 +723,11 @@ class BooleanField(Field):
|
||||
kwargs['blank'] = True
|
||||
Field.__init__(self, *args, **kwargs)
|
||||
|
||||
def deconstruct(self):
|
||||
name, path, args, kwargs = super(BooleanField, self).deconstruct()
|
||||
del kwargs['blank']
|
||||
return name, path, args, kwargs
|
||||
|
||||
def get_internal_type(self):
|
||||
return "BooleanField"
|
||||
|
||||
@ -733,6 +831,18 @@ class DateField(Field):
|
||||
kwargs['blank'] = True
|
||||
Field.__init__(self, verbose_name, name, **kwargs)
|
||||
|
||||
def deconstruct(self):
|
||||
name, path, args, kwargs = super(DateField, self).deconstruct()
|
||||
if self.auto_now:
|
||||
kwargs['auto_now'] = True
|
||||
del kwargs['editable']
|
||||
del kwargs['blank']
|
||||
if self.auto_now_add:
|
||||
kwargs['auto_now_add'] = True
|
||||
del kwargs['editable']
|
||||
del kwargs['blank']
|
||||
return name, path, args, kwargs
|
||||
|
||||
def get_internal_type(self):
|
||||
return "DateField"
|
||||
|
||||
@ -927,6 +1037,14 @@ class DecimalField(Field):
|
||||
self.max_digits, self.decimal_places = max_digits, decimal_places
|
||||
Field.__init__(self, verbose_name, name, **kwargs)
|
||||
|
||||
def deconstruct(self):
|
||||
name, path, args, kwargs = super(DecimalField, self).deconstruct()
|
||||
if self.max_digits:
|
||||
kwargs['max_digits'] = self.max_digits
|
||||
if self.decimal_places:
|
||||
kwargs['decimal_places'] = self.decimal_places
|
||||
return name, path, args, kwargs
|
||||
|
||||
def get_internal_type(self):
|
||||
return "DecimalField"
|
||||
|
||||
@ -989,6 +1107,12 @@ class EmailField(CharField):
|
||||
kwargs['max_length'] = kwargs.get('max_length', 75)
|
||||
CharField.__init__(self, *args, **kwargs)
|
||||
|
||||
def deconstruct(self):
|
||||
name, path, args, kwargs = super(EmailField, self).deconstruct()
|
||||
# We do not exclude max_length if it matches default as we want to change
|
||||
# the default in future.
|
||||
return name, path, args, kwargs
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
# As with CharField, this will cause email validation to be performed
|
||||
# twice.
|
||||
@ -1008,6 +1132,22 @@ class FilePathField(Field):
|
||||
kwargs['max_length'] = kwargs.get('max_length', 100)
|
||||
Field.__init__(self, verbose_name, name, **kwargs)
|
||||
|
||||
def deconstruct(self):
|
||||
name, path, args, kwargs = super(FilePathField, self).deconstruct()
|
||||
if self.path != '':
|
||||
kwargs['path'] = self.path
|
||||
if self.match is not None:
|
||||
kwargs['match'] = self.match
|
||||
if self.recursive is not False:
|
||||
kwargs['recursive'] = self.recursive
|
||||
if self.allow_files is not True:
|
||||
kwargs['allow_files'] = self.allow_files
|
||||
if self.allow_folders is not False:
|
||||
kwargs['allow_folders'] = self.allow_folders
|
||||
if kwargs.get("max_length", None) == 100:
|
||||
del kwargs["max_length"]
|
||||
return name, path, args, kwargs
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
defaults = {
|
||||
'path': self.path,
|
||||
@ -1115,6 +1255,11 @@ class IPAddressField(Field):
|
||||
kwargs['max_length'] = 15
|
||||
Field.__init__(self, *args, **kwargs)
|
||||
|
||||
def deconstruct(self):
|
||||
name, path, args, kwargs = super(IPAddressField, self).deconstruct()
|
||||
del kwargs['max_length']
|
||||
return name, path, args, kwargs
|
||||
|
||||
def get_internal_type(self):
|
||||
return "IPAddressField"
|
||||
|
||||
@ -1131,12 +1276,23 @@ class GenericIPAddressField(Field):
|
||||
def __init__(self, verbose_name=None, name=None, protocol='both',
|
||||
unpack_ipv4=False, *args, **kwargs):
|
||||
self.unpack_ipv4 = unpack_ipv4
|
||||
self.protocol = protocol
|
||||
self.default_validators, invalid_error_message = \
|
||||
validators.ip_address_validators(protocol, unpack_ipv4)
|
||||
self.default_error_messages['invalid'] = invalid_error_message
|
||||
kwargs['max_length'] = 39
|
||||
Field.__init__(self, verbose_name, name, *args, **kwargs)
|
||||
|
||||
def deconstruct(self):
|
||||
name, path, args, kwargs = super(GenericIPAddressField, self).deconstruct()
|
||||
if self.unpack_ipv4 is not False:
|
||||
kwargs['unpack_ipv4'] = self.unpack_ipv4
|
||||
if self.protocol != "both":
|
||||
kwargs['protocol'] = self.protocol
|
||||
if kwargs.get("max_length", None) == 39:
|
||||
del kwargs['max_length']
|
||||
return name, path, args, kwargs
|
||||
|
||||
def get_internal_type(self):
|
||||
return "GenericIPAddressField"
|
||||
|
||||
@ -1177,6 +1333,12 @@ class NullBooleanField(Field):
|
||||
kwargs['blank'] = True
|
||||
Field.__init__(self, *args, **kwargs)
|
||||
|
||||
def deconstruct(self):
|
||||
name, path, args, kwargs = super(NullBooleanField, self).deconstruct()
|
||||
del kwargs['null']
|
||||
del kwargs['blank']
|
||||
return name, path, args, kwargs
|
||||
|
||||
def get_internal_type(self):
|
||||
return "NullBooleanField"
|
||||
|
||||
@ -1254,6 +1416,16 @@ class SlugField(CharField):
|
||||
kwargs['db_index'] = True
|
||||
super(SlugField, self).__init__(*args, **kwargs)
|
||||
|
||||
def deconstruct(self):
|
||||
name, path, args, kwargs = super(SlugField, self).deconstruct()
|
||||
if kwargs.get("max_length", None) == 50:
|
||||
del kwargs['max_length']
|
||||
if self.db_index is False:
|
||||
kwargs['db_index'] = False
|
||||
else:
|
||||
del kwargs['db_index']
|
||||
return name, path, args, kwargs
|
||||
|
||||
def get_internal_type(self):
|
||||
return "SlugField"
|
||||
|
||||
@ -1302,6 +1474,14 @@ class TimeField(Field):
|
||||
kwargs['blank'] = True
|
||||
Field.__init__(self, verbose_name, name, **kwargs)
|
||||
|
||||
def deconstruct(self):
|
||||
name, path, args, kwargs = super(TimeField, self).deconstruct()
|
||||
if self.auto_now is not False:
|
||||
kwargs["auto_now"] = self.auto_now
|
||||
if self.auto_now_add is not False:
|
||||
kwargs["auto_now_add"] = self.auto_now_add
|
||||
return name, path, args, kwargs
|
||||
|
||||
def get_internal_type(self):
|
||||
return "TimeField"
|
||||
|
||||
@ -1367,6 +1547,12 @@ class URLField(CharField):
|
||||
kwargs['max_length'] = kwargs.get('max_length', 200)
|
||||
CharField.__init__(self, verbose_name, name, **kwargs)
|
||||
|
||||
def deconstruct(self):
|
||||
name, path, args, kwargs = super(URLField, self).deconstruct()
|
||||
if kwargs.get("max_length", None) == 200:
|
||||
del kwargs['max_length']
|
||||
return name, path, args, kwargs
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
# As with CharField, this will cause URL validation to be performed
|
||||
# twice.
|
||||
|
@ -227,6 +227,17 @@ class FileField(Field):
|
||||
kwargs['max_length'] = kwargs.get('max_length', 100)
|
||||
super(FileField, self).__init__(verbose_name, name, **kwargs)
|
||||
|
||||
def deconstruct(self):
|
||||
name, path, args, kwargs = super(FileField, self).deconstruct()
|
||||
if kwargs.get("max_length", None) != 100:
|
||||
kwargs["max_length"] = 100
|
||||
else:
|
||||
del kwargs["max_length"]
|
||||
kwargs['upload_to'] = self.upload_to
|
||||
if self.storage is not default_storage:
|
||||
kwargs['storage'] = self.storage
|
||||
return name, path, args, kwargs
|
||||
|
||||
def get_internal_type(self):
|
||||
return "FileField"
|
||||
|
||||
@ -326,6 +337,14 @@ class ImageField(FileField):
|
||||
self.width_field, self.height_field = width_field, height_field
|
||||
super(ImageField, self).__init__(verbose_name, name, **kwargs)
|
||||
|
||||
def deconstruct(self):
|
||||
name, path, args, kwargs = super(ImageField, self).deconstruct()
|
||||
if self.width_field:
|
||||
kwargs['width_field'] = self.width_field
|
||||
if self.height_field:
|
||||
kwargs['height_field'] = self.height_field
|
||||
return name, path, args, kwargs
|
||||
|
||||
def contribute_to_class(self, cls, name):
|
||||
super(ImageField, self).contribute_to_class(cls, name)
|
||||
# Attach update_dimension_fields so that dimension fields declared
|
||||
|
@ -1151,6 +1151,27 @@ class ForeignKey(ForeignObject):
|
||||
)
|
||||
super(ForeignKey, self).__init__(to, ['self'], [to_field], **kwargs)
|
||||
|
||||
def deconstruct(self):
|
||||
name, path, args, kwargs = super(ForeignKey, self).deconstruct()
|
||||
# Handle the simpler arguments
|
||||
if self.db_index:
|
||||
del kwargs['db_index']
|
||||
else:
|
||||
kwargs['db_index'] = False
|
||||
if self.db_constraint is not True:
|
||||
kwargs['db_constraint'] = self.db_constraint
|
||||
if self.rel.on_delete is not CASCADE:
|
||||
kwargs['on_delete'] = self.rel.on_delete
|
||||
# Rel needs more work.
|
||||
rel = self.rel
|
||||
if self.rel.field_name:
|
||||
kwargs['to_field'] = self.rel.field_name
|
||||
if isinstance(self.rel.to, basestring):
|
||||
kwargs['to'] = self.rel.to
|
||||
else:
|
||||
kwargs['to'] = "%s.%s" % (self.rel.to._meta.app_label, self.rel.to._meta.object_name)
|
||||
return name, path, args, kwargs
|
||||
|
||||
@property
|
||||
def related_field(self):
|
||||
return self.foreign_related_fields[0]
|
||||
@ -1268,6 +1289,12 @@ class OneToOneField(ForeignKey):
|
||||
kwargs['unique'] = True
|
||||
super(OneToOneField, self).__init__(to, to_field, OneToOneRel, **kwargs)
|
||||
|
||||
def deconstruct(self):
|
||||
name, path, args, kwargs = super(OneToOneField, self).deconstruct()
|
||||
if "unique" in kwargs:
|
||||
del kwargs['unique']
|
||||
return name, path, args, kwargs
|
||||
|
||||
def contribute_to_related_class(self, cls, related):
|
||||
setattr(cls, related.get_accessor_name(),
|
||||
SingleRelatedObjectDescriptor(related))
|
||||
@ -1357,6 +1384,21 @@ class ManyToManyField(RelatedField):
|
||||
|
||||
super(ManyToManyField, self).__init__(**kwargs)
|
||||
|
||||
def deconstruct(self):
|
||||
name, path, args, kwargs = super(ManyToManyField, self).deconstruct()
|
||||
# Handle the simpler arguments
|
||||
if self.rel.db_constraint is not True:
|
||||
kwargs['db_constraint'] = self.db_constraint
|
||||
if "help_text" in kwargs:
|
||||
del kwargs['help_text']
|
||||
# Rel needs more work.
|
||||
rel = self.rel
|
||||
if isinstance(self.rel.to, basestring):
|
||||
kwargs['to'] = self.rel.to
|
||||
else:
|
||||
kwargs['to'] = "%s.%s" % (self.rel.to._meta.app_label, self.rel.to._meta.object_name)
|
||||
return name, path, args, kwargs
|
||||
|
||||
def _get_path_info(self, direct=False):
|
||||
"""
|
||||
Called by both direct an indirect m2m traversal.
|
||||
|
0
tests/field_deconstruction/__init__.py
Normal file
0
tests/field_deconstruction/__init__.py
Normal file
0
tests/field_deconstruction/models.py
Normal file
0
tests/field_deconstruction/models.py
Normal file
253
tests/field_deconstruction/tests.py
Normal file
253
tests/field_deconstruction/tests.py
Normal file
@ -0,0 +1,253 @@
|
||||
from django.test import TestCase
|
||||
from django.db import models
|
||||
|
||||
|
||||
class FieldDeconstructionTests(TestCase):
|
||||
"""
|
||||
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.assertEqual(name, None)
|
||||
field.set_attributes_from_name("is_awesome_test")
|
||||
name, path, args, kwargs = field.deconstruct()
|
||||
self.assertEqual(name, "is_awesome_test")
|
||||
# Now try with a ForeignKey
|
||||
field = models.ForeignKey("some_fake.ModelName")
|
||||
name, path, args, kwargs = field.deconstruct()
|
||||
self.assertEqual(name, None)
|
||||
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_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})
|
||||
|
||||
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_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": 75})
|
||||
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"})
|
||||
|
||||
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)
|
||||
name, path, args, kwargs = field.deconstruct()
|
||||
self.assertEqual(path, "django.db.models.FilePathField")
|
||||
self.assertEqual(args, [])
|
||||
self.assertEqual(kwargs, {"recursive": True, "allow_folders": True})
|
||||
|
||||
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):
|
||||
field = models.ForeignKey("auth.User")
|
||||
name, path, args, kwargs = field.deconstruct()
|
||||
self.assertEqual(path, "django.db.models.ForeignKey")
|
||||
self.assertEqual(args, [])
|
||||
self.assertEqual(kwargs, {"to": "auth.User"})
|
||||
field = models.ForeignKey("something.Else")
|
||||
name, path, args, kwargs = field.deconstruct()
|
||||
self.assertEqual(path, "django.db.models.ForeignKey")
|
||||
self.assertEqual(args, [])
|
||||
self.assertEqual(kwargs, {"to": "something.Else"})
|
||||
field = models.ForeignKey("auth.User", on_delete=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})
|
||||
|
||||
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):
|
||||
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"})
|
||||
|
||||
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)
|
||||
name, path, args, kwargs = field.deconstruct()
|
||||
self.assertEqual(path, "django.db.models.SlugField")
|
||||
self.assertEqual(args, [])
|
||||
self.assertEqual(kwargs, {"db_index": False})
|
||||
|
||||
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_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, {})
|
Loading…
Reference in New Issue
Block a user