I'm new to Django. I am building an app that requires a lot of control over user access to various use and features.
For this I created a model called 'UserType' that has some user groups as objects i.e. scanner, overwatch, lancer and admin.
Another model, AssignedType, assigns users to one or more UserType. It has two fields. 'user' which is related to User model and 'user_type' which is related to UserType model.
The file which controls access rights (rights.py) is as follows:
from .models import User, UserType, AssignedType
# Get all user types in the database as model objects
scanner = UserType.objects.get(id=1)
overwatch = UserType.objects.get(id=2)
lancer = UserType.objects.get(id=3)
admin = UserType.objects.get(id=4)
# Rights of each type of user. Keys are the views and values are the user types allowed to access a particular view
group_rights = {
'scanner':[scanner, admin],
}
# Function to determine whether the logged user may access a view. Returns True if allowed. False otherwise.
def is_user_permitted(logged_user, view):
# Get a list of users types assigned to the user
assigned_types_objects = AssignedType.objects.all().filter(user=logged_user)
assigned_types = []
for assigned_type in assigned_types_objects:
assigned_types.append(assigned_type.user_type)
# Get a list of users types permitted to access the view.
view_rights = group_rights[view]
# Check whether there is any user type is common in the two lists. If so, user is authorized to access the view.
if set(assigned_types) & set(view_rights):
return True
else:
return False
And the view that calls the function in the above file is as follows:
@login_required
def scanner(request):
if not is_user_permitted(request.user, 'scanner'):
raise PermissionDenied
return render(request, "DataMech/scanner.html")
Everything appears to be working fine. However I am receiving an error when I try to create and run a test. Following is my tests.py file.
from django.test import TestCase, Client
from django.urls import reverse
from DataMech.models import User, UserType, AssignedType
class TestScanner(TestCase):
def setUp(self):
User.objects.create(username='scanner1', password='abc')
User.objects.create(username='scanner2', password='abc')
User.objects.create(username='overwatch1', password='abc')
User.objects.create(username='overwatch2', password='abc')
User.objects.create(username='lancer1', password='abc')
User.objects.create(username='lancer2', password='abc')
User.objects.create(username='lancer3', password='abc')
User.objects.create(username='lancer4', password='abc')
User.objects.create(username='admin1', password='abc')
UserType.objects.create(name='scanner')
UserType.objects.create(name='overwatch')
UserType.objects.create(name='lancer')
UserType.objects.create(name='admin')
AssignedType.objects.create(user='scanner1', user_type='scanner')
AssignedType.objects.create(user='scanner2', user_type='scanner')
AssignedType.objects.create(user='overwatch1', user_type='overwatch')
AssignedType.objects.create(user='overwatch2', user_type='overwatch')
AssignedType.objects.create(user='lancer1', user_type='lancer')
AssignedType.objects.create(user='lancer2', user_type='lancer')
AssignedType.objects.create(user='lancer3', user_type='lancer')
AssignedType.objects.create(user='lancer4', user_type='lancer')
AssignedType.objects.create(user='admin1', user_type='admin')
def test_allow_access_only_if_user_is_authorized_GET(self):
c = Client()
c.login(username='scanner1', password='abc')
response = c.get(reverse('scanner'))
self.assertEquals(response.status_code, 200)
self.assertTemplateUsed(response, 'DataMech/scanner.html')
c.logout()
c = Client()
c.login(username='scanner2', password='abc')
response = c.get(reverse('scanner'))
self.assertEquals(response.status_code, 200)
self.assertTemplateUsed(response, 'DataMech/scanner.html')
c.logout()
c = Client()
c.login(username='overwatch1', password='abc')
response = c.get(reverse('scanner'))
self.assertEquals(response.status_code, 403)
c.logout()
Running this test causes the following error.
Traceback (most recent call last):
File "C:\Users\Dell\Desktop\Financial reports project\FinData\FinData\manage.py", line 22, in <module>
main()
File "C:\Users\Dell\Desktop\Financial reports project\FinData\FinData\manage.py", line 18, in main
execute_from_command_line(sys.argv)
File "C:\Python39\lib\site-packages\django\core\management\__init__.py", line 401, in execute_from_command_line
utility.execute()
File "C:\Python39\lib\site-packages\django\core\management\__init__.py", line 395, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "C:\Python39\lib\site-packages\django\core\management\commands\test.py", line 23, in run_from_argv
super().run_from_argv(argv)
File "C:\Python39\lib\site-packages\django\core\management\base.py", line 330, in run_from_argv
self.execute(*args, **cmd_options)
File "C:\Python39\lib\site-packages\django\core\management\base.py", line 371, in execute
output = self.handle(*args, **options)
File "C:\Python39\lib\site-packages\django\core\management\commands\test.py", line 53, in handle
failures = test_runner.run_tests(test_labels)
File "C:\Python39\lib\site-packages\django\test\runner.py", line 698, in run_tests
self.run_checks(databases)
File "C:\Python39\lib\site-packages\django\test\runner.py", line 636, in run_checks
call_command('check', verbosity=self.verbosity, databases=databases)
File "C:\Python39\lib\site-packages\django\core\management\__init__.py", line 168, in call_command
return command.execute(*args, **defaults)
File "C:\Python39\lib\site-packages\django\core\management\base.py", line 371, in execute
output = self.handle(*args, **options)
File "C:\Python39\lib\site-packages\django\core\management\commands\check.py", line 63, in handle
self.check(
File "C:\Python39\lib\site-packages\django\core\management\base.py", line 392, in check
all_issues = checks.run_checks(
File "C:\Python39\lib\site-packages\django\core\checks\registry.py", line 70, in run_checks
new_errors = check(app_configs=app_configs, databases=databases)
File "C:\Python39\lib\site-packages\django\core\checks\urls.py", line 13, in check_url_config
return check_resolver(resolver)
File "C:\Python39\lib\site-packages\django\core\checks\urls.py", line 23, in check_resolver
return check_method()
File "C:\Python39\lib\site-packages\django\urls\resolvers.py", line 408, in check
for pattern in self.url_patterns:
File "C:\Python39\lib\site-packages\django\utils\functional.py", line 48, in __get__
res = instance.__dict__[self.name] = self.func(instance)
File "C:\Python39\lib\site-packages\django\urls\resolvers.py", line 589, in url_patterns
patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
File "C:\Python39\lib\site-packages\django\utils\functional.py", line 48, in __get__
res = instance.__dict__[self.name] = self.func(instance)
File "C:\Python39\lib\site-packages\django\urls\resolvers.py", line 582, in urlconf_module
return import_module(self.urlconf_name)
File "C:\Python39\lib\importlib\__init__.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1030, in _gcd_import
File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 790, in exec_module
File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
File "C:\Users\Dell\Desktop\Financial reports project\FinData\FinData\FinData\urls.py", line 21, in <module>
path("", include("DataMech.urls")),
File "C:\Python39\lib\site-packages\django\urls\conf.py", line 34, in include
urlconf_module = import_module(urlconf_module)
File "C:\Python39\lib\importlib\__init__.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1030, in _gcd_import
File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 790, in exec_module
File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
File "C:\Users\Dell\Desktop\Financial reports project\FinData\FinData\DataMech\urls.py", line 4, in <module>
from . import views
File "C:\Users\Dell\Desktop\Financial reports project\FinData\FinData\DataMech\views.py", line 12, in <module>
from .rights import is_user_permitted
File "C:\Users\Dell\Desktop\Financial reports project\FinData\FinData\DataMech\rights.py", line 4, in <module>
scanner = UserType.objects.get(id=1)
File "C:\Python39\lib\site-packages\django\db\models\manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "C:\Python39\lib\site-packages\django\db\models\query.py", line 429, in get
raise self.model.DoesNotExist(
DataMech.models.DoesNotExist: UserType matching query does not exist.
What am I doing wrong here?
In your views you import the rights.py
file. When your tests start there is no UserType
instances created. When Django tries to set up so that it can start your tests it gets this error because of this fact. You should use the get_or_create
method instead to ensure that the objects are created:
scanner, created = UserType.objects.get_or_create(name='scanner')
And so on. You should also adjust your tests for this by not creating the objects there or using this method.