Fixed #22001 -- Ensure db_type is respected.
db_parameters should respect an already existing db_type method and return that as its type string. In particular, this was causing some fields from gis to not be generated. Thanks to @bigsassy and @blueyed for their work on the patch. Also fixed #22260
This commit is contained in:
parent
37f7f233f5
commit
d22b291890
1
AUTHORS
1
AUTHORS
|
@ -147,6 +147,7 @@ answer newbie questions, and generally made Django that much better:
|
||||||
Ricardo Javier Cárdenes Medina <ricardo.cardenes@gmail.com>
|
Ricardo Javier Cárdenes Medina <ricardo.cardenes@gmail.com>
|
||||||
Jeremy Carbaugh <jcarbaugh@gmail.com>
|
Jeremy Carbaugh <jcarbaugh@gmail.com>
|
||||||
Graham Carlyle <graham.carlyle@maplecroft.net>
|
Graham Carlyle <graham.carlyle@maplecroft.net>
|
||||||
|
Eric Palakovich Carr <carreric@gmail.com>
|
||||||
Juan Catalano <catalanojuan@gmail.com>
|
Juan Catalano <catalanojuan@gmail.com>
|
||||||
Antonio Cavedoni <http://cavedoni.com/>
|
Antonio Cavedoni <http://cavedoni.com/>
|
||||||
cedric@terramater.net
|
cedric@terramater.net
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
from django.db import models, migrations
|
||||||
|
import django.contrib.gis.db.models.fields
|
||||||
|
|
||||||
|
|
||||||
|
# Used for regression test of ticket #22001: https://code.djangoproject.com/ticket/22001
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Neighborhood',
|
||||||
|
fields=[
|
||||||
|
(u'id', models.AutoField(verbose_name=u'ID', serialize=False, auto_created=True, primary_key=True)),
|
||||||
|
('name', models.TextField(unique=True)),
|
||||||
|
('geom', django.contrib.gis.db.models.fields.MultiPolygonField(srid=4326, null=True)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
},
|
||||||
|
bases=(models.Model,),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Household',
|
||||||
|
fields=[
|
||||||
|
(u'id', models.AutoField(verbose_name=u'ID', serialize=False, auto_created=True, primary_key=True)),
|
||||||
|
('neighborhood', models.ForeignKey(to='gis.Neighborhood', to_field=u'id', null=True)),
|
||||||
|
('address', models.TextField()),
|
||||||
|
('zip_code', models.IntegerField(null=True, blank=True)),
|
||||||
|
('geom', django.contrib.gis.db.models.fields.PointField(srid=4326, null=True, geography=True)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
},
|
||||||
|
bases=(models.Model,),
|
||||||
|
)
|
||||||
|
]
|
|
@ -0,0 +1,47 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.core.management import call_command
|
||||||
|
from django.db import connection
|
||||||
|
from django.test import override_settings, override_system_checks, TransactionTestCase
|
||||||
|
|
||||||
|
|
||||||
|
class MigrateTests(TransactionTestCase):
|
||||||
|
"""
|
||||||
|
Tests running the migrate command in Geodjango.
|
||||||
|
"""
|
||||||
|
available_apps = ["django.contrib.gis"]
|
||||||
|
|
||||||
|
def get_table_description(self, table):
|
||||||
|
with connection.cursor() as cursor:
|
||||||
|
return connection.introspection.get_table_description(cursor, table)
|
||||||
|
|
||||||
|
def assertTableExists(self, table):
|
||||||
|
with connection.cursor() as cursor:
|
||||||
|
self.assertIn(table, connection.introspection.get_table_list(cursor))
|
||||||
|
|
||||||
|
def assertTableNotExists(self, table):
|
||||||
|
with connection.cursor() as cursor:
|
||||||
|
self.assertNotIn(table, connection.introspection.get_table_list(cursor))
|
||||||
|
|
||||||
|
@override_system_checks([])
|
||||||
|
@override_settings(MIGRATION_MODULES={"gis": "django.contrib.gis.tests.migrations.migrations"})
|
||||||
|
def test_migrate_gis(self):
|
||||||
|
"""
|
||||||
|
Tests basic usage of the migrate command when a model uses Geodjango
|
||||||
|
fields. Regression test for ticket #22001:
|
||||||
|
https://code.djangoproject.com/ticket/22001
|
||||||
|
"""
|
||||||
|
# Make sure no tables are created
|
||||||
|
self.assertTableNotExists("migrations_neighborhood")
|
||||||
|
self.assertTableNotExists("migrations_household")
|
||||||
|
# Run the migrations to 0001 only
|
||||||
|
call_command("migrate", "gis", "0001", verbosity=0)
|
||||||
|
# Make sure the right tables exist
|
||||||
|
self.assertTableExists("gis_neighborhood")
|
||||||
|
self.assertTableExists("gis_household")
|
||||||
|
# Unmigrate everything
|
||||||
|
call_command("migrate", "gis", "zero", verbosity=0)
|
||||||
|
# Make sure it's all gone
|
||||||
|
self.assertTableNotExists("gis_neighborhood")
|
||||||
|
self.assertTableNotExists("gis_household")
|
|
@ -511,7 +511,7 @@ class Field(RegisterLookupMixin):
|
||||||
connection.
|
connection.
|
||||||
"""
|
"""
|
||||||
# The default implementation of this method looks at the
|
# The default implementation of this method looks at the
|
||||||
# backend-specific DATA_TYPES dictionary, looking up the field by its
|
# backend-specific data_types dictionary, looking up the field by its
|
||||||
# "internal type".
|
# "internal type".
|
||||||
#
|
#
|
||||||
# A Field class can implement the get_internal_type() method to specify
|
# A Field class can implement the get_internal_type() method to specify
|
||||||
|
@ -525,24 +525,20 @@ class Field(RegisterLookupMixin):
|
||||||
# mapped to one of the built-in Django field types. In this case, you
|
# mapped to one of the built-in Django field types. In this case, you
|
||||||
# can implement db_type() instead of get_internal_type() to specify
|
# can implement db_type() instead of get_internal_type() to specify
|
||||||
# exactly which wacky database column type you want to use.
|
# exactly which wacky database column type you want to use.
|
||||||
params = self.db_parameters(connection)
|
data = DictWrapper(self.__dict__, connection.ops.quote_name, "qn_")
|
||||||
if params['type']:
|
try:
|
||||||
if params['check']:
|
return connection.creation.data_types[self.get_internal_type()] % data
|
||||||
return "%s CHECK (%s)" % (params['type'], params['check'])
|
except KeyError:
|
||||||
else:
|
return None
|
||||||
return params['type']
|
|
||||||
return None
|
|
||||||
|
|
||||||
def db_parameters(self, connection):
|
def db_parameters(self, connection):
|
||||||
"""
|
"""
|
||||||
Replacement for db_type, providing a range of different return
|
Extension of db_type(), providing a range of different return
|
||||||
values (type, checks)
|
values (type, checks).
|
||||||
|
This will look at db_type(), allowing custom model fields to override it.
|
||||||
"""
|
"""
|
||||||
data = DictWrapper(self.__dict__, connection.ops.quote_name, "qn_")
|
data = DictWrapper(self.__dict__, connection.ops.quote_name, "qn_")
|
||||||
try:
|
type_string = self.db_type(connection)
|
||||||
type_string = connection.creation.data_types[self.get_internal_type()] % data
|
|
||||||
except KeyError:
|
|
||||||
type_string = None
|
|
||||||
try:
|
try:
|
||||||
check_string = connection.creation.data_type_check_constraints[self.get_internal_type()] % data
|
check_string = connection.creation.data_type_check_constraints[self.get_internal_type()] % data
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
|
|
@ -74,3 +74,8 @@ class JSONField(six.with_metaclass(models.SubfieldBase, models.TextField)):
|
||||||
if value is None:
|
if value is None:
|
||||||
return None
|
return None
|
||||||
return json.dumps(value)
|
return json.dumps(value)
|
||||||
|
|
||||||
|
|
||||||
|
class CustomTypedField(models.TextField):
|
||||||
|
def db_type(self, connection):
|
||||||
|
return 'custom_field'
|
||||||
|
|
|
@ -3,9 +3,10 @@ from __future__ import unicode_literals
|
||||||
import inspect
|
import inspect
|
||||||
|
|
||||||
from django.core import serializers
|
from django.core import serializers
|
||||||
|
from django.db import connection
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
from .fields import Small
|
from .fields import Small, CustomTypedField
|
||||||
from .models import DataModel, MyModel, OtherModel
|
from .models import DataModel, MyModel, OtherModel
|
||||||
|
|
||||||
|
|
||||||
|
@ -104,3 +105,10 @@ class CustomField(TestCase):
|
||||||
data = dict(inspect.getmembers(MyModel))
|
data = dict(inspect.getmembers(MyModel))
|
||||||
self.assertIn('__module__', data)
|
self.assertIn('__module__', data)
|
||||||
self.assertEqual(data['__module__'], 'field_subclassing.models')
|
self.assertEqual(data['__module__'], 'field_subclassing.models')
|
||||||
|
|
||||||
|
|
||||||
|
class TestDbType(TestCase):
|
||||||
|
|
||||||
|
def test_db_parameters_respects_db_type(self):
|
||||||
|
f = CustomTypedField()
|
||||||
|
self.assertEqual(f.db_parameters(connection)['type'], 'custom_field')
|
||||||
|
|
Loading…
Reference in New Issue