Django

Code

Ticket #2495 (new)

Opened 4 years ago

Last modified 5 months ago

db.models.TextField cannot be marked unique when using mysql backend

Reported by: anonymous Assigned to: Honza_Kral
Milestone: 1.3 Component: Database layer (models, ORM)
Version: SVN Keywords: mysql TextField
Cc: treborhudson@gmail.com, martin@akoha.com, django-ticket-2495@codef0x.org, Almad Triage Stage: Accepted
Has patch: 1 Needs documentation: 0
Needs tests: 0 Patch needs improvement: 0

Description

When I used a field like this:

text     = models.TextField(maxlength=2048, unique=True)

it results in the following sql error when the admin app goes to make the table

_mysql_exceptions.OperationalError: (1170, "BLOB/TEXT column 'text' used in key specification without a key length")

After a bit of investigation, it turns out that mysql refuses to use unique with the column unless it is only for an indexed part of the text field:

CREATE TABLE `quotes` ( `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,     `text` longtext NOT NULL ,     `submitTS` datetime NOT NULL,     `submitIP` char(15) NOT NULL,     `approved` bool NOT NULL, unique (text(1000))); 

Of course 1000 is just an arbitrary number I chose, it happens to be the maximum my database would allow.

Not entirely sure how this can be fixed, but I figured it was worth mentioning.

Attachments

hack-mysql-TextField-index.patch (1.3 kB) - added by mizatservercave on 02/22/09 23:25:47.
Preliminary hack against Django 1.0.2final
hack-mysql-TextField-index.diff (1.4 kB) - added by mizatservercave on 02/22/09 23:29:29.
Preliminary hack against Django 1.0.2final
2495-against-10914.diff (2.4 kB) - added by Honza_Kral on 06/05/09 17:21:56.
Added tests and cleaned up the patch a bit
2495-against-13302.diff (8.2 kB) - added by Honza_Kral on 05/27/10 10:53:40.
another approach to the problem, including rework of #12234

Change History

08/07/06 11:35:31 changed by anonymous

errr... to be clear, the SQL I quoted is the working syntax, not what django generates.

09/19/06 10:56:17 changed by mico@politelita.ru

have same error. what to do?

09/20/06 12:22:32 changed by anonymous

Is there a known work around?

01/10/07 17:44:26 changed by anonymous

Same problem here. Any workaround in place?

01/18/07 04:34:37 changed by Simon G. <dev@simon.net.nz>

  • keywords set to mysql TextField.
  • stage changed from Unreviewed to Accepted.

A workaround is to leave the unique=true requirement off when you create the table, and run an ALTER TABLE query to create the required index, before re-adding unique=true to the model.

Unfortunately a patch for this is not as easy as I thought it would be - you can't just find the CREATE line in management.py and change the UNIQUE line when the backend is mysql, and the field type is a blog/longtext. As far as I know there's no way to create a UNIQUE index with a blob in this way - this has to be added later to the create table command after the field specifications as a KEY constraint, or run later as an ALTER TABLE command.

08/29/07 07:01:21 changed by anonymous

dfgsdfgsdfg

01/07/08 16:40:36 changed by Simon Greenhill <dev@simon.net.nz>

#6336 was marked as a duplicate.

04/13/08 10:30:24 changed by Rob Hudson <treborhudson@gmail.com>

  • cc set to treborhudson@gmail.com.
  • version set to queryset-refactor.

This is true for qs_rf as well... perhaps we can fix it there so when it's merged this will be fixed?

Note: Jacob's jellyroll project exposes this bug since it uses a TextField? with an index. I believe this was change from an IntegerField? to a TextField? when Flickr surpassed 32-bit integer IDs for their photos.

04/14/08 21:13:19 changed by mtredinnick

  • keywords changed from mysql TextField to mysql TextField qs-rf.
  • version changed from queryset-refactor to SVN.

Ticket is not specific to queryset-refactor. Fixing the version.

04/24/08 11:50:29 changed by mtredinnick

  • keywords changed from mysql TextField qs-rf to mysql TextField.

This doesn't really have anything to do with qs-rf, so removing the keyword. It's not a blocker for that branch.

07/18/08 18:53:57 changed by Simon Greenhill

& #7750 was a duplicate

01/08/09 10:42:59 changed by martin

  • cc changed from treborhudson@gmail.com to treborhudson@gmail.com, martin@akoha.com.

02/22/09 23:25:47 changed by mizatservercave

  • attachment hack-mysql-TextField-index.patch added.

Preliminary hack against Django 1.0.2final

02/22/09 23:29:29 changed by mizatservercave

  • attachment hack-mysql-TextField-index.diff added.

Preliminary hack against Django 1.0.2final

02/22/09 23:32:54 changed by mizatservercave

  • needs_better_patch set to 1.
  • has_patch set to 1.
  • needs_tests set to 1.

Patch(es) added. For some reason Trac is reluctant to show the patch summary.

This is a quick-n-dirty 'first-cut' at making models.TextField? index-enabled when using MySQL.

It has had only very basic testing done (syncdb works and MySQL shows an index installed).

I suspect the method used in this patch can probably be improved upon greatly, and so I refer to this patch as a 'hack'.

Tests are encouraged.

02/22/09 23:35:41 changed by mizatservercave

  • cc changed from treborhudson@gmail.com, martin@akoha.com to treborhudson@gmail.com, martin@akoha.com, django-ticket-2495@codef0x.org.

For the record, I asked Django to install an index for me by setting a model.TextField? like so:

name = models.TextField?(max_length=256, db_index=True)

This made syncdb complain, so I hushed it. :)

06/05/09 15:40:40 changed by Almad

  • cc changed from treborhudson@gmail.com, martin@akoha.com, django-ticket-2495@codef0x.org to treborhudson@gmail.com, martin@akoha.com, django-ticket-2495@codef0x.org, Almad.

06/05/09 17:21:56 changed by Honza_Kral

  • attachment 2495-against-10914.diff added.

Added tests and cleaned up the patch a bit

06/05/09 17:25:18 changed by Honza_Kral

  • owner changed from nobody to Honza_Kral.
  • needs_better_patch deleted.
  • needs_tests deleted.

Added a new patch that have tests (failing without the patch) and more updated magic number. After discussing with jacob on #django-dev I only fixed the db_index property and not unique or unique_together since that doesn't make much sense for TextFields

Please let me know it the approach taken in the patch is not welcome and I will update it.

(follow-up: ↓ 19 ) 11/25/09 15:17:57 changed by dannyman@toldme.com

Hello,

How do I replace the constraint with ALTER TABLE?

My class boils down to:

class Tag(models.Model):
 name = models.TextField(max_length=32, primary_key=True)
 # Needed for syncdb.  See: http://code.djangoproject.com/ticket/2495
 #name = models.TextField(max_length=32)

So, I ran syncdb using the latter line, and it ran . . . now I'm in mysql . . .

mysql> describe events_tag;
+-------+----------+------+-----+---------+----------------+
| Field | Type     | Null | Key | Default | Extra          |
+-------+----------+------+-----+---------+----------------+
| id    | int(11)  | NO   | PRI | NULL    | auto_increment |
| name  | longtext | NO   |     | NULL    |                |
+-------+----------+------+-----+---------+----------------+
2 rows in set (0.01 sec)

mysql> alter table events_tag add primary key(name);
ERROR 1170 (42000): BLOB/TEXT column 'name' used in key specification without a key length
mysql> alter table events_tag add unique key(name);
ERROR 1170 (42000): BLOB/TEXT column 'name' used in key specification without a key length
mysql> alter table events_tag add unique index(name);
ERROR 1170 (42000): BLOB/TEXT column 'name' used in key specification without a key length

My main concern is that the tag name be unique. Do I have to set that in MySQL, or will Django enforce this for me, or do I have to implement this check within the class? (I already have a save method which does some sanity checking before a new tag can be added, so throwing a duplicate check in there aint a big deal . . .)

Thanks!

Sincerely, -daniel

12/04/09 13:59:21 changed by dannyman@toldme.com

A work-around is to use CharField? instead of TextField?.

-danny

(in reply to: ↑ 17 ) 12/28/09 16:19:21 changed by Honza_Kral

Replying to dannyman@toldme.com:

Hello, How do I replace the constraint with ALTER TABLE? mysql> alter table events_tag add primary key(name); ERROR 1170 (42000): BLOB/TEXT column 'name' used in key specification without a key length

well, specify a key length: mysql> alter table events_tag add primary key(name(255)); should work

12/28/09 16:21:26 changed by Honza_Kral

  • milestone set to 1.2.

Marking for 1.2 to get some attention. I am happy to rewrite the patch/tests if something is missing on inadequate.

03/10/10 20:24:03 changed by russellm

  • milestone changed from 1.2 to 1.3.

Not critical for 1.2

05/27/10 10:53:40 changed by Honza_Kral

  • attachment 2495-against-13302.diff added.

another approach to the problem, including rework of #12234


Add/Change #2495 (db.models.TextField cannot be marked unique when using mysql backend)




Change Properties
Action