django-scopes
django-scopes copied to clipboard
Error when scoping the user model
Hi @raphaelm
First off, thanks for creating this package!
I'm having an issue when trying to apply scopes to the user model. I have a multi-tenancy application, and I only want users to be able to see other users in their same tenancy.
Here's a snippet of my core/models.py
file based on the example in the docs:
from django.db import models
from django.contrib.auth.models import AbstractUser, UserManager
from django_scopes import ScopedManager
from phonenumber_field.modelfields import PhoneNumberField
from tenants.models import Tenant
from web.models import Sponsor
class LineOfBusiness(models.Model):
LINE_OF_BUSINESS_CHOICES = [
("COMM", "Commercial"),
("EX", "Exchange"),
("MA", "Medicaid"),
("MC", "Medicare"),
("WC", "Workers' Compensation"),
]
line_of_business = models.CharField(choices=LINE_OF_BUSINESS_CHOICES, max_length=5)
def __str__(self):
return self.get_line_of_business_display()
class User(AbstractUser):
USER_TYPE_CHOICES = [
("C", "Customer"),
("E", "Employee"),
]
tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE)
phone_number = PhoneNumberField(blank=True)
line_of_business = models.ManyToManyField(LineOfBusiness)
sponsors = models.ManyToManyField(Sponsor)
user_type = models.CharField(choices=USER_TYPE_CHOICES, max_length=5)
# https://github.com/raphaelm/django-scopes#scoping-the-user-model
objects = ScopedManager(tenant='tenant', _manager_class=UserManager)
Here's the error I get when I try to create the migrations:
root@80f003450656:/django_scope_test# python manage.py makemigrations core
Traceback (most recent call last):
File "manage.py", line 25, in <module>
main()
File "manage.py", line 21, in main
execute_from_command_line(sys.argv)
File "/usr/local/lib/python3.8/site-packages/django/core/management/__init__.py", line 401, in execute_from_command_line
utility.execute()
File "/usr/local/lib/python3.8/site-packages/django/core/management/__init__.py", line 395, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/usr/local/lib/python3.8/site-packages/django/core/management/base.py", line 328, in run_from_argv
self.execute(*args, **cmd_options)
File "/usr/local/lib/python3.8/site-packages/django/core/management/base.py", line 369, in execute
output = self.handle(*args, **options)
File "/usr/local/lib/python3.8/site-packages/django/core/management/base.py", line 83, in wrapped
res = handle_func(*args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/django/core/management/commands/makemigrations.py", line 164, in handle
changes = autodetector.changes(
File "/usr/local/lib/python3.8/site-packages/django/db/migrations/autodetector.py", line 43, in changes
changes = self._detect_changes(convert_apps, graph)
File "/usr/local/lib/python3.8/site-packages/django/db/migrations/autodetector.py", line 129, in _detect_changes
self.new_apps = self.to_state.apps
File "/usr/local/lib/python3.8/site-packages/django/utils/functional.py", line 48, in __get__
res = instance.__dict__[self.name] = self.func(instance)
File "/usr/local/lib/python3.8/site-packages/django/db/migrations/state.py", line 209, in apps
return StateApps(self.real_apps, self.models)
File "/usr/local/lib/python3.8/site-packages/django/db/migrations/state.py", line 272, in __init__
self.render_multiple([*models.values(), *self.real_models])
File "/usr/local/lib/python3.8/site-packages/django/db/migrations/state.py", line 307, in render_multiple
model.render(self)
File "/usr/local/lib/python3.8/site-packages/django/db/migrations/state.py", line 576, in render
body.update(self.construct_managers())
File "/usr/local/lib/python3.8/site-packages/django/db/migrations/state.py", line 535, in construct_managers
as_manager, manager_path, qs_path, args, kwargs = manager.deconstruct()
File "/usr/local/lib/python3.8/site-packages/django/db/models/manager.py", line 61, in deconstruct
raise ValueError(
ValueError: Could not find manager Manager in django_scopes.manager.
Please note that you need to inherit from managers you dynamically generated with 'from_queryset()'.
Any help you can provide would be greatly appreciated!
After experimenting further, it seems like django.contrib.auth.models.BaseUserManager
allows the migrations to run successfully.
Interesting :thinking: Have you tested that this only happens for the user model and not for other models? I haven't tried all this with the user model before, but I don't see why it should fail.
@raphaelm what finally worked for me was this:
from django.db import models
from django.contrib.auth.models import AbstractUser, UserManager
from django_scopes import ScopedManager
from phonenumber_field.modelfields import PhoneNumberField
from tenants.models import Tenant
from web.models import Sponsor
class LineOfBusiness(models.Model):
LINE_OF_BUSINESS_CHOICES = [
("COMM", "Commercial"),
("EX", "Exchange"),
("MA", "Medicaid"),
("MC", "Medicare"),
("WC", "Workers' Compensation"),
]
line_of_business = models.CharField(choices=LINE_OF_BUSINESS_CHOICES, max_length=5)
def __str__(self):
return self.get_line_of_business_display()
class MyUserManager(UserManager):
use_in_migrations = False
class User(AbstractUser):
USER_TYPE_CHOICES = [
("C", "Customer"),
("E", "Employee"),
]
tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE)
phone_number = PhoneNumberField(blank=True)
line_of_business = models.ManyToManyField(LineOfBusiness)
sponsors = models.ManyToManyField(Sponsor)
user_type = models.CharField(choices=USER_TYPE_CHOICES, max_length=5)
# https://github.com/raphaelm/django-scopes#scoping-the-user-model
objects = ScopedManager(tenant='tenant', _manager_class=MyUserManager)
Any idea why use_in_migrations
causes the error? I have scoping applied to other models (although they are not using a custom manager class), and they all work fine.
I have the same issue with my User model!