django 1.7+ default_permissions
由于做Caption要做权限设计。在核心类的设计的时候需要做好权限的基础设计。django 1.7+以后 django.db.modes新增特性 default_permissions,官方文档语焉不详。
决定自己探索下,不想一一分析代码,遂引入bug,直接观察核心线路。
引入bug方法:
class baseModel(models.Model): #.... class Meta: default_permissions='add'#should be ('add','change',...)
错误如下:
Traceback (most recent call last): File "C:\Users\tommy.yu\Desktop\Captain\Captain-master\codes\Captain\manage.py", line 10, in <module> execute_from_command_line(sys.argv) File "C:\Python27\lib\site-packages\django-1.7.2-py2.7.egg\django\core\management\__init__.py", line 385, in execute_from_command_line utility.execute() File "C:\Python27\lib\site-packages\django-1.7.2-py2.7.egg\django\core\management\__init__.py", line 377, in execute self.fetch_command(subcommand).run_from_argv(self.argv) File "C:\Python27\lib\site-packages\django-1.7.2-py2.7.egg\django\core\management\base.py", line 288, in run_from_argv self.execute(*args, **options.__dict__) File "C:\Python27\lib\site-packages\django-1.7.2-py2.7.egg\django\core\management\base.py", line 338, in execute output = self.handle(*args, **options) File "C:\Python27\lib\site-packages\django-1.7.2-py2.7.egg\django\core\management\commands\migrate.py", line 165, in handle emit_post_migrate_signal(created_models, self.verbosity, self.interactive, connection.alias) File "C:\Python27\lib\site-packages\django-1.7.2-py2.7.egg\django\core\management\sql.py", line 268, in emit_post_migrate_signal using=db) File "C:\Python27\lib\site-packages\django-1.7.2-py2.7.egg\django\dispatch\dispatcher.py", line 198, in send response = receiver(signal=self, sender=sender, **named) File "C:\Python27\lib\site-packages\django-1.7.2-py2.7.egg\django\contrib\auth\management\__init__.py", line 114, in create_permissions Permission.objects.using(using).bulk_create(perms) File "C:\Python27\lib\site-packages\django-1.7.2-py2.7.egg\django\db\models\query.py", line 409, in bulk_create self._batched_insert(objs_without_pk, fields, batch_size) File "C:\Python27\lib\site-packages\django-1.7.2-py2.7.egg\django\db\models\query.py", line 938, in _batched_insert using=self.db) File "C:\Python27\lib\site-packages\django-1.7.2-py2.7.egg\django\db\models\manager.py", line 92, in manager_method return getattr(self.get_queryset(), name)(*args, **kwargs) File "C:\Python27\lib\site-packages\django-1.7.2-py2.7.egg\django\db\models\query.py", line 921, in _insert return query.get_compiler(using=using).execute_sql(return_id) File "C:\Python27\lib\site-packages\django-1.7.2-py2.7.egg\django\db\models\sql\compiler.py", line 920, in execute_sql cursor.execute(sql, params) File "C:\Python27\lib\site-packages\django-1.7.2-py2.7.egg\django\db\backends\utils.py", line 81, in execute return super(CursorDebugWrapper, self).execute(sql, params) File "C:\Python27\lib\site-packages\django-1.7.2-py2.7.egg\django\db\backends\utils.py", line 65, in execute return self.cursor.execute(sql, params) File "C:\Python27\lib\site-packages\django-1.7.2-py2.7.egg\django\db\utils.py", line 94, in __exit__ six.reraise(dj_exc_type, dj_exc_value, traceback) File "C:\Python27\lib\site-packages\django-1.7.2-py2.7.egg\django\db\backends\utils.py", line 65, in execute return self.cursor.execute(sql, params) File "C:\Python27\lib\site-packages\django-1.7.2-py2.7.egg\django\db\backends\sqlite3\base.py", line 486, in execute return Database.Cursor.execute(self, query, params) django.db.utils.IntegrityError: columns content_type_id, codename are not unique
直接在最终的文件C:\Python27\lib\site-packages\django-1.7.2-py2.7.egg\django\db\backends\sqlite3\base.py里面加入print xxx之类的语句。如下:
def execute(self, query, params=None): if params is None: return Database.Cursor.execute(self, query) query = self.convert_query(query) print query,params#在这里添加了print return Database.Cursor.execute(self, query, params)
再次migrate,并观察sql:
由于sql过多,只抓出insert的sql,如下:
INSERT INTO "auth_permission" ("name", "content_type_id", "codename") SELECT ? AS "name", ? AS "content_type_id", ? AS "codename" UNION ALL SELECT ?, ?, ? UNION ALL SELECT ?, ?, ? ... ( u'Can add tag', 7, u'add_tag', u'Can change tag', 7, u'change_tag', u'Can delete tag', 7, u'delete_tag', ... )
即写表auth_permission ,django的权限表,可以参考这里。
经过反复的try发现,default_permissions只是取出 default_permissions[0],default_permissions[1],default_permissions[2]然后将其插入到数据表auth_permission里面。而且版本1.7.2的还有bug:
case 1. str类型赋值
default_permissions='abcde'
sql如下,以上代码为抽象基类中的meta类,对于子类(Tag,ContentType,Menu,Page)来说,只有最后一个Page起到作用了(id为10)
INSERT INTO "auth_permission" ("name", "content_type_id", "codename") SELECT ? AS "name", ? AS "content_type_id", ? AS "codename" UNION ALL SELECT ?, ?, ? UNION A LL SELECT ?, ?, ? UNION ALL SELECT ?, ?, ? UNION ALL SELECT ?, ?, ? UNION ALL SELECT ?, ?, ? UNION ALL SELECT ?, ?, ? UNION ALL SELECT ?, ?, ? UNION ALL SELECT ?, ?, ? UNION ALL SELECT ?, ?, ? UNION ALL SELECT ?, ?, ? UNION ALL SELECT ?, ?, ? UNION ALL SELECT ?, ?, ? UNION ALL SELECT ?, ?, ? (u'Can add tag', 7, u'add_tag', u'Can change tag', 7, u'change_tag', u'Can delete tag', 7, u'delete_tag', u'Can add content type', 8, u'add_contenttype', u'Can change content type', 8, u'change_contenttype', u'Can delete content type', 8, u'delete_contenttype', u'Can add menu', 9, u'add_menu', u'Can change menu', 9, u'change_menu', u'Can delete menu', 9, u'delete_menu', u'Can a page', 10, 'a_page', u'Can b page', 10, 'b_page', u'Can c page', 10, 'c_page', u'Can d page', 10, 'd_page', u'Can e page', 10, 'e_page')
case 2. tuple/list ,长度小于3
抽象基类default_permissions属性
default_permissions=('add', 'change')
生成的sql代码:
INSERT INTO "auth_permission" ("name", "content_type_id", "codename") SELECT ? AS "name", ? AS "content_type_id", ? AS "codename" UNION ALL SELECT ?, ?, ? UNION A LL SELECT ?, ?, ? UNION ALL SELECT ?, ?, ? UNION ALL SELECT ?, ?, ? UNION ALL SELECT ?, ?, ? UNION ALL SELECT ?, ?, ? UNION ALL SELECT ?, ?, ? UNION ALL SELECT ?, ?, ? UNION ALL SELECT ?, ?, ? UNION ALL SELECT ?, ?, ? (u'Can add tag', 7, u'add_tag', u'Can change tag', 7, u'change_tag', u'Can delete tag', 7, u'delete_tag', u'Can add content type', 8, u'add_contenttype', u'Can change content type', 8, u'change_contenttype', u'Can delete content type', 8, u'delete_contenttype', u'Can add menu', 9, u'add_menu', u'Can change menu', 9, u'change_menu', u'Can delete menu', 9, u'delete_menu', u'Can add page', 10, 'add_page', u'Can change page', 10,'change_page')
跟case 1 差不多,有作用,有bug。
结论:
往表auth_permissions里面插入记录而已。
鉴于只对子类中的最后一个模型起作用(包括permissions属性),因此不能作为公共属性。