zlorf/django-dbsettings

Invalid ContentType after running "migrate" command

Opened this issue · 9 comments

When using django 1.7 migrations i get the following message:

> ./manage migrate
...
The following content types are stale and need to be deleted:
    core |

core - is my app where i use django-dbsettings.

I found this closed ticket in django bugtracker: https://code.djangoproject.com/ticket/23519
Here is code which creates content-type with empty model: https://github.com/zlorf/django-dbsettings/blob/master/dbsettings/management.py#L13

    ct, created = ContentType.objects.get_or_create(model='', app_label=appname,
                                                    defaults={'name': appname})

To fix this we need to tell django "we need this model, so don't touch this" or find another way to implement app-level permissions.

Thanks for the info and a bug-report link.
Indeed some action need to be taken. Let me think a while.

@zlorf any update on this issue? I'm gonna need to migrate to something else

@vahidm it's safe to just ignore that warnings

zlorf commented

@vahidm No update so far, but this message (warning) is only annoying, not harmful.

I know +1s aren't exactly helpful, but for what it's worth… I'd love a fix for this. I took a look myself and noped out of there pretty quickly; it doesn't seem like an obvious change would solve it.

I also run into this since a while. It took my attention when I run 'migrate.py migrate' in my Jenkins deployment script. Unfortunately the deployment stuck at this point. A workaround is to use 'migrate.py migrate --no-input'. But this solution only skips that warning and don't solve the issue.

The general issue ist that permissions from django.auth are bound to models. But in dbsettings you want to bind the permission to an app. The only model you may bind the permission to is the dbsetting.models.Settings. So maybe you could change the dbsettings.management.mk_permissions:

    ct, created = ContentType.objects.get_or_create(model='', app_label=appname,
                                                    defaults={'name': appname})

to

    ct, created = ContentType.objects.get_or_create(model='settings', 
                                                    app_label='dbsettings')

(I don't know what 'name' is good for. I remember some changes in Django that this field was removed)

and

if are_global_settings:
        permission = (
            'can_edit__settings',
            'Can edit %s non-model settings' % app_label,
        )

to

if are_global_settings:
        permission = (
            'can_edit_%s_settings' % app_label,
            'Can edit %s non-model settings' % app_label,
        )

After a look at my database I found a lot of can_edit__settings with different description strings:

 959 | Can edit myapp1 non-model settings               |             199 | can_edit__settings
 974 | Can edit myapp2 non-model settings                    |             214 | can_edit__settings
 975 | Can edit myapp3 non-model settings                      |             215 | can_edit__settings
 976 | Can edit myapp4 non-model settings                       |             216 | can_edit__settings
 977 | Can edit myapp5 non-model settings                 |             217 | can_edit__settings
 978 | Can edit myapp6 non-model settings                   |             218 | can_edit__settings
 979 | Can edit myapp7 non-model settings                       |             219 | can_edit__settings
 980 | Can edit myapp8 non-model settings               |             220 | can_edit__settings

Is this a bug? Should the name of the permission be like in my proposal above? I can't see how this could work.

The disadvantage of this approach is, that you may have some 'stale' permissions. Some thoughts about this:

1.) Ignore this issue. Django does the same on removed permissions in the code. :)
2.) Write a management command for cleanup
3.) This permissions must not be deleted automatically. When you run your project in a different configuration without one of the apps that uses dbsettings, this would delete permissions that my required by another instance of your project.
4.) Remove app specific settings. Currently I can't see that the app specific settings for permissions are working at all.

If you want I can have a look at the implementation and create a PR. Unfortunately this change may break a lot of application that use the permissions.

Any thoughts?

zlorf commented

No bug here, can_edit__settings is a permission name indicating that it control app-level settings permission (model == '', hence can_edit__settings instead of can_edit_MODEL_settings for model-level settings permission).

I need to rethink the permissions here, and I like the idea of binding app-level permissions to Settings model instead of non-existing model of an app.

Ok. That's good. So I missed something.

I think the Settings model is the only suitable model. I was thinking about models from django (e.g. django.auth.models.Permission). But this somehow hurts my feelings. :-)