django: adding custom permissions stopped working - django

I have a django project with multiple apps. In one of the apps when I add custom permissions to any model and run makemigration, the migration-file to add the permission is created. When I apply the migration I get no error messages but the permission isn't added to the auth_permission table.
class Meta:
app_label = 'my_app'
permissions = (
('assign_work_type', 'Assign work type'),
)
The migration completes without errors
I have tried doing the same in other apps and that works. I have also tried adding a column to the current app and that works as well. Anyone got any idea what it could be? I am running django 1.11.26
UPDATE
Here is the content of the migration file
# -*- coding: utf-8 -*-
# Generated by Django 1.11.26 on 2019-11-25 11:13
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('timereport', '0143_auto_20191122_1754'),
]
operations = [
migrations.AlterModelOptions(
name='worktype',
options={'permissions': (('assign_work_type', 'Assign work type'),)},
),
]

After quite some investigation I found that the affected app was missing the models_module, i.e. the "models.py" file. I have all my models in a /model/ directory and a while back I deleted the models.py file thinking it was of no use.
Adding the models.py file back solved the issue

Related

Migrating models of dependencies when changing DEFAULT_AUTO_FIELD

I'm using Django 3.2. I've changed added this line to settings.py:
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
I then ran these commands:
$ python manage.py makemigrations
$ python manage.py migrate
The makemigrations command creates new migration files for my apps, not just the apps that I have created, but also in my dependencies. For example, I'm using django-allauth, and this file was created in my virtual environment (virtualenv):
.venv/lib/python3.8/site-packages/allauth/account/migrations/0003_auto_20210408_1526.py
This file is not shipped with django-allauth. When I deploy this application from git, this file is not included.
What should I do instead? How can I switch DEFAULT_AUTO_FIELD without the need to create new migration files for dependencies like django-allauth?
Ideally, your third party dependencies would include this line in the config found in apps.py:
from django.apps import AppConfig
class ExampleConfig(AppConfig):
default_auto_field = 'django.db.models.AutoField'
While waiting for upstream dependencies to update their apps.py or migration files, you can override the app config yourself. If it doesn't exist already, create an apps.py file in your main app directory (eg: project/apps.py), and override the config of a dependency. In this example, I'm overriding the config of django-allauth:
from allauth.account.apps import AccountConfig
from allauth.socialaccount.apps import SocialAccountConfig
class ModifiedAccountConfig(AccountConfig):
default_auto_field = 'django.db.models.AutoField'
class ModifiedSocialAccountConfig(SocialAccountConfig):
default_auto_field = 'django.db.models.AutoField'
Then modify INSTALLED_APPS in settings.py to look like this, replacing the old entries for django-allauth in this example:
INSTALLED_APPS = [
# ....
# replace: "allauth.account", with
"projectname.apps.ModifiedAccountConfig",
# replace: "allauth.socialaccount", with
"projectname.apps.ModifiedSocialAccountConfig",
]
If the dependency doesn't have an apps.py file to override, you can still create an AppConfig sub-class in project/apps.py like this:
from django.apps import AppConfig
class ModifiedExampleDependencyConfig(AppConfig):
name = 'exampledependency' # the python module
default_auto_field = 'django.db.models.AutoField'
Now when you run python manage.py makemigrations, no migration files should be created for the dependencies.
I work on a big project, we upgraded Django from 2.2. to 3.2 and then have got a need to create all new models with Big Integer (Int8) (PostgreSQL) field instead of default Integer (Int4).
When I defined it in settings.py:
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
I got the same problem, but with own apps - Django tried to make me to migrate 135 models I had, but I didn't want to do it. I only wanted to create new models with BigInt and manipuate olds manually.
I found the next solution. I changed the field to custom:
DEFAULT_AUTO_FIELD = 'project.db.models.CustomBigAutoField'
And then overrided its deconstruction:
from django.db import models
class CustomBigAutoField(models.BigAutoField):
"""Int8 field that is applied only for new models."""
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
if getattr(self, 'model', None):
path = 'django.db.models.AutoField'
return name, path, args, kwargs
As I discovered, fields of new models don't have a back reference to their models, so path wouldn't be overridden for them.
We override path because Django checks whether a model is changed by a key, that includes the path to this field. So we deceive Django and it thinks that existing model didn't changed.
I might not see the whole picture, but I tested it with different existing and new models and it worked for me. If someone tells me why this solution is bad, I'd be grateful.

django-oscar RuntimeError: conflicting models

Version Info: Python 2.7, Django 1.9, Oscar Commerce - VERSION = (1.3)
I am trying to customize Products and few other models in the catalogue app following the documentation.
I have forked catalogue app (to myproject/forked_apps/catalogue) as per documentation documentation and did this in models.py:
from django.db import models
from oscar.apps.catalogue.abstract_models import AbstractProduct
class Product(AbstractProduct):
is_active = models.BooleanField(default=False)
from oscar.apps.catalogue.models import *
I have already included the modified catalogue app, in the INSTALLED_APPS in settings.py as an argument for get_core_apps function, as stated in docs (so my local app is replacing the original app from Oscar).
INSTALLED_APPS = [
...
] + get_core_apps(['forked_apps.catalogue'])
Migrations are also copied from oscar.apps.catalogue to my local app.
When I'm trying to make migrations I'm getting this error all the time:
RuntimeError: Conflicting 'product_product_options' models in application 'catalogue': <class 'oscar.apps.catalogue.models.Product_product_options'> and <class 'forked_apps.catalogue.models.Product_product_options'>.
I tried to remove all migrations from my local catalogue app (the I copied before from Oscar app), then it works, but all new migrations are created in Oscar source code folder, but I need them to be in my project...
How do I get over this error ?
Make sure you're using the following wherever you use the Product model:
from oscar.core.loading import get_model
Product = get_model('catalogue', 'Product')
if you, in some place of your code write an import just like this:
from oscar.apps.catalogue.models import Product
you will ran into this issue.

right way to create a django data migration that creates a group?

I would like to create data migrations that create Permissions and Groups, so that my other developers can just run the migrations and get everything set up. I was able to create the migrations and run them just fine, but now I'm getting an error when running my tests.
But if I do this:
from django.contrib.auth.models import Group
def add_operations_group(apps, schema_editor):
Group.objects.get_or_create(name='operations')
I get:
django.db.utils.OperationalError: no such table: auth_group
If I do this:
def add_operations_group(apps, schema_editor):
Group = apps.get_model("django.contrib.auth", "group")
Group.objects.get_or_create(name='operations')
I get:
LookupError: No installed app with label 'django.contrib.auth'
Is there a way to do this? Or is there a "Django Way" to make sure things like permissions and groups are created?
This is how I do it:
from django.db import models, migrations
def apply_migration(apps, schema_editor):
Group = apps.get_model('auth', 'Group')
Group.objects.bulk_create([
Group(name=u'group1'),
Group(name=u'group2'),
Group(name=u'group3'),
])
def revert_migration(apps, schema_editor):
Group = apps.get_model('auth', 'Group')
Group.objects.filter(
name__in=[
u'group1',
u'group2',
u'group3',
]
).delete()
class Migration(migrations.Migration):
dependencies = [
('someapp', 'XXXX_some_migration'),
]
operations = [
migrations.RunPython(apply_migration, revert_migration)
]
Although, there must be a more Djangonic way.
Answer from César is correct. To make it more Django create the migration file automatically by going to your django app root folder and entering:
python manage.py makemigrations <yourappname> --empty
Note: You may need python3 instead of python depending on your system configuration.
This creates an empty migration file in a sub directory of your app called 0001_initial.py
You can then alter it as per César instructions. Which worked correctly with Django 2.2

ValueError: Related model u'app.model' cannot be resolved

I have two applications (ook and eek say) and I want to use a foreign key to a model in ook from a model in eek. Both are in INSTALLED_APPS with ook first.
In ook.models.py, i have:
class Fubar(models.Model):
...
In eek.models.py, I have:
class monkey(models.Model):
external = models.ForeignKey('ook.Fubar', blank=True, null=True)
...
The migration generated is:
class Migration(migrations.Migration):
dependencies = [
('eek', '0002_auto_20151029_1040'),
]
operations = [
migrations.AlterField(
model_name='monkey',
name='external',
field=models.ForeignKey(blank=True, to='ook.Fubar', null=True),
),
]
When I run the migration, I get this error:
...
1595 raise ValueError('Foreign Object from and to fields must be
the same non-zero length')
1596 if isinstance(self.rel.to, six.string_types):
-> 1597 raise ValueError('Related model %r cannot be resolved' % self.rel.to)
1598 related_fields = []
1599 for index in range(len(self.from_fields)):
ValueError: Related model u'ook.Fubar' cannot be resolved
What am I doing wrong?
Because You have ForeignKey in operations, You must add a ook to dependencies:
dependencies = [
('ook', '__first__'),
('eek', '0002_auto_20151029_1040'),
]
Django migrations have two "magic" values:
__first__ - get module first migration
__latest__ - get module latest migration
Try running migrations one by one for every model.
This way you can debug the app you are facing problem with
python manage.py migrate appmname
I just got the same error, but referring to a model that was declared as part of the same migration. It turned out that the first migrations.CreateModel(...) referred to a not yet declared model. I manually moved this below the declaration of the referred model and then everything worked fine.
In my case, It was the cache and previous migrations that resulted in this error. I removed __pycache__ and migrations folder and then re-run the migrations command and it worked.
Remember, when you'll do python manage.py makemigrations it won't see any new migrations and will console output no changes detected. You'll have to do python manage.py makemigrations your_app_name instead to make things work.
I encountered this error when trying to use a child model of a base model as a foreign key. It makes sense that it didn't work because there's not an id field on the child model. My fix was to use the parent on the key. Unfortunately this was not immediately intuitive and set me back a couple hours.
I have found that it looks like this bug was not fixed yet when you scroll down to the bottom.
Django ValueError: Related model cannot be resolved Bug
I am using 1.11.7, they are talking about 1.9.3.
It worked everything on localhost, but was always failing on Heroku, so I tested all the options/answers above and nothing worked.
Then I have noticed, localhost DB in Admin I had 1 profile created (1 DB record), went to Heroku and DB has 0 records for Profile table so I have added 1, pushed the migration, python manage.py migrate and all it went OK.
That validates that I did not need to change any of those migrations manually that all is working.
Maybe it will help to someone.
migrations
# -*- coding: utf-8 -*-
# Generated by Django 1.11.7 on 2017-11-23 21:26
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('blog', '0005_blog_author'),
]
operations = [
migrations.AlterField(
model_name='blog',
name='author',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE,
to='core.Profile'),
),
]
order of dependencies is too important.
in your case, ook must be created first then depend eek on it.
dependencies= [
('ook', '0001_initial'),
('eek', '0002_auto_20151029_1040'),
]

How install a extension in postgresql before creating the models in django?

Using django 1.8 + Postgres 9+, I have models with custom PG datatypes (like ltree). Creating de database from zero fail because
CREATE EXTENSION ltree;
is not executed. I try with a empty migration, but that run after the models creation. Exist a way to run sql before the models creation?
I know this is unanswered for long, and maybe now you already have figured out the answer. But I'm posting just in case someone gets a little bit of help from this.
For extensions that are available in Postgres
If the extension is one of the defaults that are available with Postgres, then you can simply create first migration as this, and then load other migrations.
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.contrib.postgres.operations import HStoreExtension
from django.db import migrations
class Migration(migrations.Migration):
run_before = [
('some_app_that_requires_hstore', '0001_initial'),
]
operations = [
HStoreExtension(),
]
Notice the use of run_before. It is the exact opposite of dependencies. Alternatively, you can make this migration as say 1st one and load all others after this using dependencies.
In case this migration fails to create an extension because of privileges issues, then you can simply use the superuser and nosuperuser in Postgres to temporarily provide privileges for the current user to run migrations like:
ALTER ROLE user_name superuser;
# create the extension and then remove the superuser privileges.
ALTER ROLE user_name nosuperuser;
For third-party extensions that are not available in Postgres
For third-party extensions, you can use run_python, to load the extension for you like:
from django.db import migrations
def create_third_party_extension(apps, schema_editor):
schema_editor.execute("CREATE EXTENSION my_custom_extension;")
def drop_third_party_extension(apps, schema_editor):
schema_editor.execute("DROP EXTENSION IF EXISTS my_custom_extension;")
class Migration(migrations.Migration):
dependencies = [
('venues', '0001_auto_20180607_1014'),
]
operations = [
migrations.RunPython(create_third_party_extension, reverse_code=drop_third_party_extension, atomic=True)
]
Alternatively, you can just have them as a part of your deployment scripts instead of migrations.
I hope this helps.
You can also install the extension on the template database, and when new databases are created (like when running tests), the new database will copy that template and include the extension.
psql -d template1 -c 'create extension if not exists hstore;'