Opened 3 years ago

Closed 2 years ago

Last modified 2 years ago

#22001 closed Bug (fixed)

GeoDjango (contrib.gis) does not create geometry columns in 1.7a2

Reported by: steko Owned by: bigsassy
Component: GIS Version: master
Severity: Release blocker Keywords:
Cc: bigsassy, django@… Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no


I am testing Django 1.7a2 on a very small project+app.

So far, with both PostGIS and SpatiaLite I have found the following problem. Basically the geometry column is included in the file, but not in the SQL migration.

from django.contrib.gis.db import models

# Create your models here.

class Location(models.Model):
    name = models.CharField(max_length=100)
    geom = models.PointField(srid=2100)
    objects = models.GeoManager()

    def __unicode__(self):

0001 myapp/

# encoding: utf8
from django.db import models, migrations
import django.contrib.gis.db.models.fields

class Migration(migrations.Migration):

    dependencies = [

    operations = [
                (u'id', models.AutoField(verbose_name=u'ID', serialize=False, auto_created=True, primary_key=True)),
                ('name', models.CharField(max_length=100)),
                ('geom', django.contrib.gis.db.models.fields.PointField(srid=2100)),

Output from sqlmigrate:

(venv)[steko@ogma myproject]$ python sqlmigrate myapp 0001
CREATE TABLE "myapp_location" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(100) NOT NULL);

This happens both with PostGIS and SpatiaLite. Perhaps obvious: it works well with Django 1.6. My current system is Fedora 20.

Change History (36)

comment:1 Changed 3 years ago by steko

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset

Something went wrong with my submission: apologies.

sqlmigrate output with PostGIS (index but no column):

CREATE TABLE "elisapp_location" ("id" serial NOT NULL PRIMARY KEY, "name" varchar(100) NOT NULL);
CREATE INDEX "elisapp_location_geom_id" ON "elisapp_location" USING GIST ("geom" );

Forgot to add that I am using Python 2.7.5 and Django is installed in a virtualenv.

Version 0, edited 3 years ago by steko (next)

comment:2 Changed 3 years ago by mjtamlyn

  • Severity changed from Normal to Release blocker
  • Triage Stage changed from Unreviewed to Accepted

I haven't verified this, but assuming it is the case then it's definitely a release blocker.

comment:3 follow-up: Changed 3 years ago by anonymous

I also ran into this problem with a project. The root of the problem comes from the data_types dict inside postgres and sqlite's DatabaseCreation classes. This dict appears to be responsible for matching a field defined in the model to it's proper SQL statement:

# django/db/backends/postgresql_psycopg2/
data_types = {
    'AutoField': 'serial',
    'BinaryField': 'bytea',
    'BooleanField': 'boolean',
    'CharField': 'varchar(%(max_length)s)',
    # ... snip ...
    'TimeField': 'time',

The DatabaseCreation class at django/db/backends/sqlite3/ is suffers from the same problem, which is none of the GeometryFields are defined in this dict. It could look something like this if it was fixed:

# django/db/backends/postgresql_psycopg2/
data_types = {
    'AutoField': 'serial',
    'BinaryField': 'bytea',
    'BooleanField': 'boolean',
    'CharField': 'varchar(%(max_length)s)',
    # ... snip ...
    'TimeField': 'time',
    # Add an entry for each Geometry field in Geodjango
    'PointField': 'geometry(POINT,%(srid))'
    'LineStringField': 'geometry(LINESTRING,%(srid))'
    # ... etc ...

That appears to be the fix from my brief look over the code. But I worry that I'm missing something.

comment:4 Changed 3 years ago by bigsassy

Oh, and I made the above comment. I forgot to login.

comment:5 Changed 3 years ago by dfunckt

FWIW, #21909 is related to this ticket, which I opened and then closed as invalid as I couldn't reproduce it anymore. The attached test project might save someone a couple of minutes.

comment:6 in reply to: ↑ 3 Changed 3 years ago by steko

Replying to anonymous:

I also ran into this problem with a project. The root of the problem comes from the data_types dict inside postgres and sqlite's DatabaseCreation classes.

So given this is specific to contrib.gis probably the patch should be in django/contrib/gis/db/backends/spatialite/ and django/contrib/gis/db/backends/postgis/ respectively, I think?

comment:7 Changed 3 years ago by bigsassy

  • Cc bigsassy added
  • Owner changed from nobody to bigsassy
  • Status changed from new to assigned

comment:8 Changed 2 years ago by bigsassy

  • Has patch set
  • Triage Stage changed from Accepted to Ready for checkin

Ok, I've submitted a pull request for this ticket:

I have a few things I'm worried about:

  • I duplicated some supporting test code from django/tests/migrations to django/django/contrib/gis/tests/migrations.
  • I don't have any tests to make sure changing special geo-specific attributes for fields like sridand geography create a useful migration for the changed field.
  • I only ran the test I added against postgis.

Hopefully those wiser then me can chime in and set me straight. This is my first pull request for Django, so I'm certainly open to improvements.

Also, I set the triage stage as Ready for checkin and Has patch to True. I hope that's correct.

comment:9 Changed 2 years ago by bmispelon

  • Triage Stage changed from Ready for checkin to Accepted


The ready for checkin status is for when someone has reviewed your patch and deemed it ready for a core dev to check it in.
Using the has flag checkbox is enough to indicate you've provided a patch (or in this case, a pull request).

THere's more information on our documentation if you're interested:


comment:10 follow-up: Changed 2 years ago by steko

I am not 100% sure this is the right place to raise the issue but it seems definitely related to the one that I originally reported. The sqlclear output for the same app is (perhaps obviously) missing the necessary DELETE FROM geometry_columns WHERE f_table_name = mytable; so even if the geometry column was created correctly (as happens in 1.6) clearing the database would not work as expected. I don't know if your proposed patch fixes this other issue as well.

comment:11 in reply to: ↑ 10 Changed 2 years ago by bigsassy

Replying to steko:

It "should" fix that problem too. But I'll add a test or two for altering migrations (e.g. deleting a geometry field in a model).

Last edited 2 years ago by bigsassy (previous) (diff)

comment:12 Changed 2 years ago by andrewgodwin

  • Owner changed from bigsassy to andrewgodwin

comment:13 Changed 2 years ago by shai

I Left some comments on the PR; at this time, it is not yet RFC.

comment:14 Changed 2 years ago by bigsassy

Thanks, shai. I'll try and address your comments tonight, assuming I haven't been booted off the ticket.

Given Andrew has taken ownership of the ticket, does that mean I should stop? I'm eager to contribute something to Django (particularly if it's related to Geodjango), but I understand if Andrew wants to take care of a blocker himself.

comment:15 Changed 2 years ago by shai

I believe Andrew intended to imply that he's taking responsibility for the ticket, being a blocker in the migrations. I'd expect that, if he thought your whole approach is wrong, he'd say so. I'm sure he'll appreciate all the help he can get.

comment:16 Changed 2 years ago by andrewgodwin

Shai is right, I just claimed it due to lack of activity and wanting to put it on my to do list. Please reclaim it if you want to keep going!

comment:17 Changed 2 years ago by bigsassy

  • Owner changed from andrewgodwin to bigsassy

Well alright then. Yoink!

comment:18 Changed 2 years ago by shai

  • Needs tests set
  • Patch needs improvement set

#22260 (just opened) appears to be related.

comment:19 Changed 2 years ago by blueyed

@andrewgodwin: with #22260 the issue is that db_type is not called, but only db_parameters, and its get_internal_type return value is not present in the lookup table (with django-durationfield).

Here is a proposed pull request:

comment:20 Changed 2 years ago by blueyed

It seems like @andrewgodwin changed the behavior of db_type in

It is unclear if the CHECK (%s) suffix added there is used and was made intentionally, since calls to db_type have been replaced with calls to db_parameters.

comment:21 Changed 2 years ago by bigsassy

Ok, I added in @blueyed's code into my pull request. I haven't added any more tests yet though. Currently there's one test added to the gis contrib app that checks the Creation operation forwards and backwards with GeometryField fields.

I'm happy to add more, but the test I've added seems to cover the error in this ticket (i.e. fails without the fix). And the changes from @blueyed causes the test to pass, so yay?

Let me know what else needs to be done.

Last edited 2 years ago by bigsassy (previous) (diff)

comment:22 Changed 2 years ago by blueyed

  • Cc django@… added

The documentation should probably get verified/clarified:

The :meth:.db_type method is called by Django when the framework
constructs the CREATE TABLE statements for your application -- that is,
when you first create your tables. It is also called when constructing a
WHERE clause that includes the model field -- that is, when you retrieve data
using QuerySet methods like get(), filter(), and exclude() and have
the model field as an argument. It's not called at any other time, so it can afford to
execute slightly complex code, such as the connection.settings_dict check in
the above example.

comment:23 Changed 2 years ago by bigsassy

  • Needs tests unset

comment:24 Changed 2 years ago by bigsassy

  • Needs documentation set

comment:25 Changed 2 years ago by Marc Tamlyn <marc.tamlyn@…>

  • Resolution set to fixed
  • Status changed from assigned to closed

In d22b291890c1736a40c0ad97448c7318df2eebb2:

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

comment:26 Changed 2 years ago by timo

  • Has patch unset
  • Needs documentation unset
  • Patch needs improvement unset
  • Resolution fixed deleted
  • Status changed from closed to new

This broke the build and the follow up commit 834d78ffc3a7eb62d55ac269f83ac0e7473662ea did not resolve all the issues as there are still many errors when running the GIS tests.

comment:27 Changed 2 years ago by bigsassy

Ugh, I'm sorry for breaking the build. I'm trying to resolve the errors reported in Jenkins.

I'm running into one problem, though. My test I added is breaking when ran against MySQL. I think I've now resolved the problem (pull request coming), and I'm now trying to run the test using MySQL for the database and I'm getting an error:

Failed to install index for distapp.SouthTexasZipcode model: (1252, 'All parts of a SPATIAL index must be NOT NULL')

That's coming from this model:

class SouthTexasZipcode(NamedModel):
    "Model for a few South Texas ZIP codes."
    poly = models.PolygonField(srid=32140, null=True)

I'm new to using mysql as a GIS (I've always used PostGIS), but from what I'm reading MySQL spatial fields must ALWAYS be declared with NOT NULL. This would mean the null=True is the cause of the problem here.

Which means there's always been a problem. Which is impossible. So what am I doing wrong? Here's how I have the settings file setup for running the tests:

    'default': {
        'ENGINE': 'django.contrib.gis.db.backends.mysql',
        'NAME': 'django_default',
        'USER': '<insert user>',
        'PASSWORD': '<insert password>',
        'OPTIONS': {
            'init_command': 'SET storage_engine=MyISAM',
    'other': {
        'ENGINE': 'django.contrib.gis.db.backends.mysql',
        'NAME': 'django_other',
        'USER': '<insert user>',
        'PASSWORD': '<insert password>',
        'OPTIONS': {
            'init_command': 'SET storage_engine=MyISAM',

SECRET_KEY = "django_tests_secret_key"

# Use a fast hasher to speed up tests.

Last edited 2 years ago by bigsassy (previous) (diff)

comment:28 Changed 2 years ago by timo

The warning on Jenkins (from a build that passed) is: Failed to install index for distapp.SouthTexasZipcode model: (1464, "The used table type doesn't support SPATIAL indexes").

I guess Jenkins uses InnoDB rather than MyISAM. Does the warning you encountered cause any errors/failures or prevent the tests from running?

comment:29 Changed 2 years ago by bigsassy

Yes, the error I receive prevents the tests from running. I should note I had received the error you mentioned at first, due to using InnoDB. Upon switching the storage engine to MyISAM (see settings file above), those errors were replaced with the Failed to install index for distapp.SouthTexasZipcode model: (1252, 'All parts of a SPATIAL index must be NOT NULL') error.

I'll try and resolve these issues tonight, particularly looking at how Jenkins is configured when running these tests. It still seems weird that these tests weren't failing earlier, and what would have changed to cause this to start happening now.

comment:30 Changed 2 years ago by timo

I guess you should use InnoDB like Jenkins does for now. Florian pushed some fixes earlier and now there's only an error about BLOB/TEXT column 'name' used in key specification without a key length for MySQL GIS.

comment:31 Changed 2 years ago by bigsassy

Ah, good. THAT I know exactly what the problem is, and can fix right away. I'll have something ready in a little bit here.

comment:32 Changed 2 years ago by bigsassy

Ok, I created a pull request to fix that bug.

I'm still having issues getting these tests to run ing mysql, but it turns out the problem I posted above isn't the issue. Those were actually warnings, and appear in the Jenkins console log for the build you just posted. My error is actually this:

django.db.utils.ProgrammingError: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '%s ORDER BY `django_content_type`.`name` ASC' at line 1")

Does that look familiar? I'm still looking into what I may be doing wrong.

comment:33 Changed 2 years ago by bigsassy

Ok, I got it working on python 2.7 (and the regression is fixed with the PR above).

I had been running the tests earlier in python 3.2 on my ubuntu box here. I'm thinking it may be a problem with how I built the MySQL-python library for it. Anyway, the pull request above should resolve the failing test on MySQL.

comment:34 Changed 2 years ago by Tim Graham <timograham@…>

In c11b9346d4ebc10d8d98945a974016a5e85f25e6:

Fixed migration so MySQL GIS test doesn't fail; refs #22001.

The test previously failed with the error:
(1170, "BLOB/TEXT column 'name' used in key specification without a key length")

comment:35 Changed 2 years ago by timo

  • Resolution set to fixed
  • Status changed from new to closed

Jenkins is back to green!

comment:36 Changed 2 years ago by bigsassy

Great! Thanks for your patience, everyone :)

Note: See TracTickets for help on using tickets.
Back to Top