~ubuntu-branches/debian/sid/python-django/sid

« back to all changes in this revision

Viewing changes to tests/inspectdb/tests.py

  • Committer: Package Import Robot
  • Author(s): Raphaël Hertzog
  • Date: 2014-09-17 14:15:11 UTC
  • mfrom: (1.3.17) (6.2.18 experimental)
  • Revision ID: package-import@ubuntu.com-20140917141511-icneokthe9ww5sk4
Tags: 1.7-2
* Release to unstable.
* Add a migrate-south sample script to help users apply their South
  migrations. Thanks to Brian May.

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
from __future__ import unicode_literals
3
3
 
4
4
import re
 
5
from unittest import skipUnless
5
6
 
6
7
from django.core.management import call_command
7
8
from django.db import connection
8
9
from django.test import TestCase, skipUnlessDBFeature
9
 
from django.utils.unittest import expectedFailure
10
10
from django.utils.six import PY3, StringIO
11
11
 
12
 
if connection.vendor == 'oracle':
13
 
    expectedFailureOnOracle = expectedFailure
14
 
else:
15
 
    expectedFailureOnOracle = lambda f: f
16
12
 
17
13
class InspectDBTestCase(TestCase):
18
14
 
21
17
        # Lets limit the introspection to tables created for models of this
22
18
        # application
23
19
        call_command('inspectdb',
24
 
                     table_name_filter=lambda tn:tn.startswith('inspectdb_'),
 
20
                     table_name_filter=lambda tn: tn.startswith('inspectdb_'),
25
21
                     stdout=out)
26
22
        error_message = "inspectdb has examined a table that should have been filtered out."
27
23
        # contrib.contenttypes is one of the apps always installed when running
43
39
 
44
40
        return assertFieldType
45
41
 
46
 
    # Inspecting oracle DB doesn't produce correct results, see #19884
47
 
    @expectedFailureOnOracle
48
42
    def test_field_types(self):
49
43
        """Test introspection of various Django field types"""
50
44
        assertFieldType = self.make_field_type_asserter()
51
45
 
52
 
        assertFieldType('char_field', "models.CharField(max_length=10)")
53
 
        assertFieldType('comma_separated_int_field', "models.CharField(max_length=99)")
 
46
        # Inspecting Oracle DB doesn't produce correct results (#19884):
 
47
        # - it gets max_length wrong: it returns a number of bytes.
 
48
        # - it reports fields as blank=True when they aren't.
 
49
        if (connection.features.can_introspect_max_length and
 
50
                not connection.features.interprets_empty_strings_as_nulls):
 
51
            assertFieldType('char_field', "models.CharField(max_length=10)")
 
52
            assertFieldType('comma_separated_int_field', "models.CharField(max_length=99)")
54
53
        assertFieldType('date_field', "models.DateField()")
55
54
        assertFieldType('date_time_field', "models.DateTimeField()")
56
 
        assertFieldType('email_field', "models.CharField(max_length=75)")
57
 
        assertFieldType('file_field', "models.CharField(max_length=100)")
58
 
        assertFieldType('file_path_field', "models.CharField(max_length=100)")
59
 
        if connection.vendor == 'postgresql':
60
 
            # Only PostgreSQL has a specific type
 
55
        if (connection.features.can_introspect_max_length and
 
56
                not connection.features.interprets_empty_strings_as_nulls):
 
57
            assertFieldType('email_field', "models.CharField(max_length=75)")
 
58
            assertFieldType('file_field', "models.CharField(max_length=100)")
 
59
            assertFieldType('file_path_field', "models.CharField(max_length=100)")
 
60
        if connection.features.can_introspect_ip_address_field:
61
61
            assertFieldType('ip_address_field', "models.GenericIPAddressField()")
62
62
            assertFieldType('gen_ip_adress_field', "models.GenericIPAddressField()")
63
 
        else:
 
63
        elif (connection.features.can_introspect_max_length and
 
64
                not connection.features.interprets_empty_strings_as_nulls):
64
65
            assertFieldType('ip_address_field', "models.CharField(max_length=15)")
65
66
            assertFieldType('gen_ip_adress_field', "models.CharField(max_length=39)")
66
 
        assertFieldType('slug_field', "models.CharField(max_length=50)")
67
 
        assertFieldType('text_field', "models.TextField()")
68
 
        assertFieldType('time_field', "models.TimeField()")
69
 
        assertFieldType('url_field', "models.CharField(max_length=200)")
 
67
        if (connection.features.can_introspect_max_length and
 
68
                not connection.features.interprets_empty_strings_as_nulls):
 
69
            assertFieldType('slug_field', "models.CharField(max_length=50)")
 
70
        if not connection.features.interprets_empty_strings_as_nulls:
 
71
            assertFieldType('text_field', "models.TextField()")
 
72
        if connection.features.can_introspect_time_field:
 
73
            assertFieldType('time_field', "models.TimeField()")
 
74
        if (connection.features.can_introspect_max_length and
 
75
                not connection.features.interprets_empty_strings_as_nulls):
 
76
            assertFieldType('url_field', "models.CharField(max_length=200)")
70
77
 
71
78
    def test_number_field_types(self):
72
79
        """Test introspection of various Django field types"""
73
80
        assertFieldType = self.make_field_type_asserter()
74
81
 
75
 
        assertFieldType('id', "models.IntegerField(primary_key=True)")
76
 
        assertFieldType('big_int_field', "models.BigIntegerField()")
77
 
        if connection.vendor == 'mysql':
78
 
            # No native boolean type on MySQL
 
82
        if not connection.features.can_introspect_autofield:
 
83
            assertFieldType('id', "models.IntegerField(primary_key=True)  # AutoField?")
 
84
 
 
85
        if connection.features.can_introspect_big_integer_field:
 
86
            assertFieldType('big_int_field', "models.BigIntegerField()")
 
87
        else:
 
88
            assertFieldType('big_int_field', "models.IntegerField()")
 
89
 
 
90
        if connection.features.can_introspect_boolean_field:
 
91
            assertFieldType('bool_field', "models.BooleanField()")
 
92
            if connection.features.can_introspect_null:
 
93
                assertFieldType('null_bool_field', "models.NullBooleanField()")
 
94
            else:
 
95
                assertFieldType('null_bool_field', "models.BooleanField()")
 
96
        else:
79
97
            assertFieldType('bool_field', "models.IntegerField()")
80
 
            assertFieldType('null_bool_field', "models.IntegerField(blank=True, null=True)")
81
 
        else:
82
 
            assertFieldType('bool_field', "models.BooleanField()")
83
 
            assertFieldType('null_bool_field', "models.NullBooleanField()")
84
 
        if connection.vendor == 'sqlite':
85
 
            # Guessed arguments, see #5014
86
 
            assertFieldType('decimal_field', "models.DecimalField(max_digits=10, decimal_places=5) "
87
 
                "# max_digits and decimal_places have been guessed, as this database handles decimal fields as float")
88
 
        else:
 
98
            if connection.features.can_introspect_null:
 
99
                assertFieldType('null_bool_field', "models.IntegerField(blank=True, null=True)")
 
100
            else:
 
101
                assertFieldType('null_bool_field', "models.IntegerField()")
 
102
 
 
103
        if connection.features.can_introspect_decimal_field:
89
104
            assertFieldType('decimal_field', "models.DecimalField(max_digits=6, decimal_places=1)")
 
105
        else:       # Guessed arguments on SQLite, see #5014
 
106
            assertFieldType('decimal_field', "models.DecimalField(max_digits=10, decimal_places=5)  "
 
107
                                             "# max_digits and decimal_places have been guessed, "
 
108
                                             "as this database handles decimal fields as float")
 
109
 
90
110
        assertFieldType('float_field', "models.FloatField()")
 
111
 
91
112
        assertFieldType('int_field', "models.IntegerField()")
92
 
        if connection.vendor == 'sqlite':
 
113
 
 
114
        if connection.features.can_introspect_positive_integer_field:
93
115
            assertFieldType('pos_int_field', "models.PositiveIntegerField()")
94
 
            assertFieldType('pos_small_int_field', "models.PositiveSmallIntegerField()")
95
116
        else:
96
 
            # 'unsigned' property undetected on other backends
97
117
            assertFieldType('pos_int_field', "models.IntegerField()")
98
 
            if connection.vendor == 'postgresql':
 
118
 
 
119
        if connection.features.can_introspect_positive_integer_field:
 
120
            if connection.features.can_introspect_small_integer_field:
 
121
                assertFieldType('pos_small_int_field', "models.PositiveSmallIntegerField()")
 
122
            else:
 
123
                assertFieldType('pos_small_int_field', "models.PositiveIntegerField()")
 
124
        else:
 
125
            if connection.features.can_introspect_small_integer_field:
99
126
                assertFieldType('pos_small_int_field', "models.SmallIntegerField()")
100
127
            else:
101
128
                assertFieldType('pos_small_int_field', "models.IntegerField()")
102
 
        if connection.vendor in ('sqlite', 'postgresql'):
 
129
 
 
130
        if connection.features.can_introspect_small_integer_field:
103
131
            assertFieldType('small_int_field', "models.SmallIntegerField()")
104
132
        else:
105
133
            assertFieldType('small_int_field', "models.IntegerField()")
110
138
        # Lets limit the introspection to tables created for models of this
111
139
        # application
112
140
        call_command('inspectdb',
113
 
                     table_name_filter=lambda tn:tn.startswith('inspectdb_'),
 
141
                     table_name_filter=lambda tn: tn.startswith('inspectdb_'),
114
142
                     stdout=out)
115
143
        output = out.getvalue()
116
144
        error_message = "inspectdb generated an attribute name which is a python keyword"
119
147
        self.assertNotIn("from = models.ForeignKey(InspectdbPeople)", output, msg=error_message)
120
148
        # As InspectdbPeople model is defined after InspectdbMessage, it should be quoted
121
149
        self.assertIn("from_field = models.ForeignKey('InspectdbPeople', db_column='from_id')",
122
 
            output)
 
150
                      output)
123
151
        self.assertIn("people_pk = models.ForeignKey(InspectdbPeople, primary_key=True)",
124
 
            output)
 
152
                      output)
125
153
        self.assertIn("people_unique = models.ForeignKey(InspectdbPeople, unique=True)",
126
 
            output)
 
154
                      output)
127
155
 
128
156
    def test_digits_column_name_introspection(self):
129
157
        """Introspection of column names consist/start with digits (#16536/#17676)"""
131
159
        # Lets limit the introspection to tables created for models of this
132
160
        # application
133
161
        call_command('inspectdb',
134
 
                     table_name_filter=lambda tn:tn.startswith('inspectdb_'),
 
162
                     table_name_filter=lambda tn: tn.startswith('inspectdb_'),
135
163
                     stdout=out)
136
164
        output = out.getvalue()
137
165
        error_message = "inspectdb generated a model field name which is a number"
153
181
        out = StringIO()
154
182
        call_command('inspectdb', stdout=out)
155
183
        output = out.getvalue()
156
 
        base_name = 'Field' if connection.vendor != 'oracle' else 'field'
 
184
        base_name = 'Field' if not connection.features.uppercases_column_names else 'field'
157
185
        self.assertIn("field = models.IntegerField()", output)
158
186
        self.assertIn("field_field = models.IntegerField(db_column='%s_')" % base_name, output)
159
187
        self.assertIn("field_field_0 = models.IntegerField(db_column='%s__')" % base_name, output)
160
188
        self.assertIn("field_field_1 = models.IntegerField(db_column='__field')", output)
161
189
        self.assertIn("prc_x = models.IntegerField(db_column='prc(%) x')", output)
162
190
        if PY3:
163
 
            # Python 3 allows non-ascii identifiers
 
191
            # Python 3 allows non-ASCII identifiers
164
192
            self.assertIn("tamaño = models.IntegerField()", output)
165
193
        else:
166
194
            self.assertIn("tama_o = models.IntegerField(db_column='tama\\xf1o')", output)
169
197
        """Test that by default the command generates models with `Meta.managed = False` (#14305)"""
170
198
        out = StringIO()
171
199
        call_command('inspectdb',
172
 
                     table_name_filter=lambda tn:tn.startswith('inspectdb_columntypes'),
 
200
                     table_name_filter=lambda tn: tn.startswith('inspectdb_columntypes'),
173
201
                     stdout=out)
174
202
        output = out.getvalue()
175
203
        self.longMessage = False
176
204
        self.assertIn("        managed = False", output, msg='inspectdb should generate unmanaged models.')
 
205
 
 
206
    @skipUnless(connection.vendor == 'sqlite',
 
207
                "Only patched sqlite's DatabaseIntrospection.data_types_reverse for this test")
 
208
    def test_custom_fields(self):
 
209
        """
 
210
        Introspection of columns with a custom field (#21090)
 
211
        """
 
212
        out = StringIO()
 
213
        orig_data_types_reverse = connection.introspection.data_types_reverse
 
214
        try:
 
215
            connection.introspection.data_types_reverse = {
 
216
                'text': 'myfields.TextField',
 
217
                'bigint': 'BigIntegerField',
 
218
            }
 
219
            call_command('inspectdb',
 
220
                         table_name_filter=lambda tn: tn.startswith('inspectdb_columntypes'),
 
221
                         stdout=out)
 
222
            output = out.getvalue()
 
223
            self.assertIn("text_field = myfields.TextField()", output)
 
224
            self.assertIn("big_int_field = models.BigIntegerField()", output)
 
225
        finally:
 
226
            connection.introspection.data_types_reverse = orig_data_types_reverse