﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
15915	Permission codename duplication is not handled well	Valentin Golev	mhaligowski	"Example:

{{{

from django.db import models

# Create your models here.


class Tweet(models.Model):
    message = models.CharField(max_length=140)

    class Meta:
        permissions = ((""change_tweet"", ""can, like, change tweet or something...""),)


}}}

Stacktrace:

{{{

(bug-with-perms)[.../bugwithperms]$ python manage.py syncdb
Creating tables ...
Creating table auth_permission
Creating table auth_group_permissions
Creating table auth_group
Creating table auth_user_user_permissions
Creating table auth_user_groups
Creating table auth_user
Creating table auth_message
Creating table django_content_type
Creating table django_session
Creating table django_site
Creating table trybug_tweet

You just installed Django's auth system, which means you don't have any superusers defined.
Would you like to create one now? (yes/no): no
Traceback (most recent call last):
  File ""manage.py"", line 14, in <module>
    execute_manager(settings)
  File ""/media/oldroot/home/valentin/Envs/bug-with-perms/lib/python2.6/site-packages/django/core/management/__init__.py"", line 438, in execute_manager
    utility.execute()
  File ""/media/oldroot/home/valentin/Envs/bug-with-perms/lib/python2.6/site-packages/django/core/management/__init__.py"", line 379, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File ""/media/oldroot/home/valentin/Envs/bug-with-perms/lib/python2.6/site-packages/django/core/management/base.py"", line 191, in run_from_argv
    self.execute(*args, **options.__dict__)
  File ""/media/oldroot/home/valentin/Envs/bug-with-perms/lib/python2.6/site-packages/django/core/management/base.py"", line 220, in execute
    output = self.handle(*args, **options)
  File ""/media/oldroot/home/valentin/Envs/bug-with-perms/lib/python2.6/site-packages/django/core/management/base.py"", line 351, in handle
    return self.handle_noargs(**options)
  File ""/media/oldroot/home/valentin/Envs/bug-with-perms/lib/python2.6/site-packages/django/core/management/commands/syncdb.py"", line 109, in handle_noargs
    emit_post_sync_signal(created_models, verbosity, interactive, db)
  File ""/media/oldroot/home/valentin/Envs/bug-with-perms/lib/python2.6/site-packages/django/core/management/sql.py"", line 190, in emit_post_sync_signal
    interactive=interactive, db=db)
  File ""/media/oldroot/home/valentin/Envs/bug-with-perms/lib/python2.6/site-packages/django/dispatch/dispatcher.py"", line 172, in send
    response = receiver(signal=self, sender=sender, **named)
  File ""/media/oldroot/home/valentin/Envs/bug-with-perms/lib/python2.6/site-packages/django/contrib/auth/management/__init__.py"", line 51, in create_permissions
    content_type=ctype
  File ""/media/oldroot/home/valentin/Envs/bug-with-perms/lib/python2.6/site-packages/django/db/models/manager.py"", line 138, in create
    return self.get_query_set().create(**kwargs)
  File ""/media/oldroot/home/valentin/Envs/bug-with-perms/lib/python2.6/site-packages/django/db/models/query.py"", line 360, in create
    obj.save(force_insert=True, using=self.db)
  File ""/media/oldroot/home/valentin/Envs/bug-with-perms/lib/python2.6/site-packages/django/db/models/base.py"", line 460, in save
    self.save_base(using=using, force_insert=force_insert, force_update=force_update)
  File ""/media/oldroot/home/valentin/Envs/bug-with-perms/lib/python2.6/site-packages/django/db/models/base.py"", line 553, in save_base
    result = manager._insert(values, return_id=update_pk, using=using)
  File ""/media/oldroot/home/valentin/Envs/bug-with-perms/lib/python2.6/site-packages/django/db/models/manager.py"", line 195, in _insert
    return insert_query(self.model, values, **kwargs)
  File ""/media/oldroot/home/valentin/Envs/bug-with-perms/lib/python2.6/site-packages/django/db/models/query.py"", line 1436, in insert_query
    return query.get_compiler(using=using).execute_sql(return_id)
  File ""/media/oldroot/home/valentin/Envs/bug-with-perms/lib/python2.6/site-packages/django/db/models/sql/compiler.py"", line 791, in execute_sql
    cursor = super(SQLInsertCompiler, self).execute_sql(None)
  File ""/media/oldroot/home/valentin/Envs/bug-with-perms/lib/python2.6/site-packages/django/db/models/sql/compiler.py"", line 735, in execute_sql
    cursor.execute(sql, params)
  File ""/media/oldroot/home/valentin/Envs/bug-with-perms/lib/python2.6/site-packages/django/db/backends/util.py"", line 34, in execute
    return self.cursor.execute(sql, params)
  File ""/media/oldroot/home/valentin/Envs/bug-with-perms/lib/python2.6/site-packages/django/db/backends/sqlite3/base.py"", line 234, in execute
    return Database.Cursor.execute(self, query, params)
django.db.utils.IntegrityError: columns content_type_id, codename are not unique

}}}

What's going on?

Basically, if there are two permissions for a model with same codenames and different descriptions, Django tries to add both in the database, but there is a unique index on codename so it all crashes horribly.

The code which is responsible for this is at create_permissions() function[1]. There is a set: `searched_perms`, so it should help to avoid duplicate values. But the second element of every tuple in set, namely ""perm"", is another tuple of (codename, name), and the ""name"" is a human-readable name and not an identifier. So if we have two permissions with same codenames, but different ""name""s, set will see them as different permissions and django will try to insert them both in the database. However, the unique index is only on two fields: ctype and codename, so permissions with same ctype and codename, but different ""names"", can't be inserted. That results in a pretty odd stacktrace.

[1]: http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/management/__init__.py#L19

Either it is a bug, or a good error message should be added. This one is misleading (and it's much more misleading on postgres). I had to use pdb to investigate this pretty innocent code"	Bug	closed	contrib.auth	1.3	Normal	fixed		me@… nikolay@…	Accepted	1	0	0	0	1	0
