|
|
|
|
@ -1,13 +1,38 @@
|
|
|
|
|
from django.test import TestCase
|
|
|
|
|
from django.test import TestCase, RequestFactory
|
|
|
|
|
from django.test.utils import override_settings
|
|
|
|
|
from django.contrib.auth import get_user_model
|
|
|
|
|
from django.contrib import admin
|
|
|
|
|
from django.contrib.admin.sites import AdminSite
|
|
|
|
|
from django.db import models
|
|
|
|
|
from django.test import RequestFactory
|
|
|
|
|
from unittest.mock import Mock
|
|
|
|
|
from rules.contrib.models import RulesModelMixin, RulesModelBase
|
|
|
|
|
|
|
|
|
|
from contrib.admin import CommonAdminMixin
|
|
|
|
|
from contrib.models import CommonModel
|
|
|
|
|
from contrib.rules import has_global_perm
|
|
|
|
|
from contrib.admin import CommonAdminMixin
|
|
|
|
|
from rules.contrib.models import RulesModelMixin, RulesModelBase
|
|
|
|
|
|
|
|
|
|
# Test model for admin customization
|
|
|
|
|
class DummyModel(models.Model):
|
|
|
|
|
field1 = models.CharField(max_length=100)
|
|
|
|
|
field2 = models.IntegerField()
|
|
|
|
|
field3 = models.BooleanField()
|
|
|
|
|
field4 = models.DateField()
|
|
|
|
|
field5 = models.TextField()
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
app_label = 'contrib'
|
|
|
|
|
|
|
|
|
|
class DummyAdmin(CommonAdminMixin, admin.ModelAdmin):
|
|
|
|
|
model = DummyModel
|
|
|
|
|
fieldsets = (
|
|
|
|
|
('Group1', {'fields': ('field1', 'field2')}),
|
|
|
|
|
('Group2', {'fields': ('field3', 'field4', 'field5')}),
|
|
|
|
|
)
|
|
|
|
|
fields = ['field1', 'field2', 'field3', 'field4', 'field5']
|
|
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
|
self.opts = self.model._meta
|
|
|
|
|
self.admin_site = AdminSite()
|
|
|
|
|
|
|
|
|
|
User = get_user_model()
|
|
|
|
|
|
|
|
|
|
@ -61,8 +86,15 @@ class GlobalPermissionRulesTestCase(TestCase):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CommonAdminMixinTestCase(TestCase):
|
|
|
|
|
@classmethod
|
|
|
|
|
def setUpTestData(cls):
|
|
|
|
|
cls.user = User.objects.create_superuser('admin', 'admin@test.com', 'password')
|
|
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
|
self.user = User.objects.create_user(username='testuser', password='testpass')
|
|
|
|
|
self.request = RequestFactory().get('/')
|
|
|
|
|
self.request.user = self.__class__.user
|
|
|
|
|
self.admin = DummyAdmin()
|
|
|
|
|
self.admin.admin_site = AdminSite()
|
|
|
|
|
|
|
|
|
|
def test_formfield_for_dbfield_with_formfield_overrides(self):
|
|
|
|
|
"""Test formfield_for_dbfield when db_field class is in formfield_overrides"""
|
|
|
|
|
@ -91,3 +123,197 @@ class CommonAdminMixinTestCase(TestCase):
|
|
|
|
|
|
|
|
|
|
# Verify that the formfield_overrides were used
|
|
|
|
|
self.assertIsNotNone(result)
|
|
|
|
|
|
|
|
|
|
def test_default_behavior(self):
|
|
|
|
|
"""Test with no customization settings"""
|
|
|
|
|
fields = self.admin.get_fields(self.request)
|
|
|
|
|
self.assertEqual(fields, ['field1', 'field2', 'field3', 'field4', 'field5'])
|
|
|
|
|
|
|
|
|
|
fieldsets = self.admin.get_fieldsets(self.request)
|
|
|
|
|
self.assertEqual(len(fieldsets), 2)
|
|
|
|
|
self.assertEqual(fieldsets[0][1]['fields'], ['field1', 'field2'])
|
|
|
|
|
self.assertEqual(fieldsets[1][1]['fields'], ['field3', 'field4', 'field5'])
|
|
|
|
|
|
|
|
|
|
@override_settings(CUSTOM_MODEL_FIELDS={
|
|
|
|
|
'contrib_dummymodel': {
|
|
|
|
|
'fields': ['field1', 'field3', 'field5']
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
def test_included_fields_only(self):
|
|
|
|
|
"""Test with only included fields specified"""
|
|
|
|
|
fields = self.admin.get_fields(self.request)
|
|
|
|
|
self.assertEqual(fields, ['field1', 'field3', 'field5'])
|
|
|
|
|
|
|
|
|
|
fieldsets = self.admin.get_fieldsets(self.request)
|
|
|
|
|
self.assertEqual(len(fieldsets), 2)
|
|
|
|
|
self.assertEqual(fieldsets[0][1]['fields'], ['field1'])
|
|
|
|
|
self.assertEqual(fieldsets[1][1]['fields'], ['field3', 'field5'])
|
|
|
|
|
|
|
|
|
|
@override_settings(CUSTOM_MODEL_FIELDS={
|
|
|
|
|
'contrib_dummymodel': {
|
|
|
|
|
'exclude': ['field2', 'field4']
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
def test_excluded_fields_only(self):
|
|
|
|
|
"""Test with only excluded fields specified"""
|
|
|
|
|
fields = self.admin.get_fields(self.request)
|
|
|
|
|
self.assertEqual(fields, ['field1', 'field3', 'field5'])
|
|
|
|
|
|
|
|
|
|
fieldsets = self.admin.get_fieldsets(self.request)
|
|
|
|
|
self.assertEqual(len(fieldsets), 2)
|
|
|
|
|
self.assertEqual(fieldsets[0][1]['fields'], ['field1'])
|
|
|
|
|
self.assertEqual(fieldsets[1][1]['fields'], ['field3', 'field5'])
|
|
|
|
|
|
|
|
|
|
@override_settings(CUSTOM_MODEL_FIELDS={
|
|
|
|
|
'contrib_dummymodel': {
|
|
|
|
|
'fields': ['field1', 'field3', 'field5'],
|
|
|
|
|
'exclude': ['field3']
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
def test_included_and_excluded_fields(self):
|
|
|
|
|
"""Test with both included and excluded fields"""
|
|
|
|
|
fields = self.admin.get_fields(self.request)
|
|
|
|
|
# custom fields should take precedence over exclude
|
|
|
|
|
self.assertEqual(fields, ['field1', 'field3', 'field5'])
|
|
|
|
|
|
|
|
|
|
fieldsets = self.admin.get_fieldsets(self.request)
|
|
|
|
|
self.assertEqual(len(fieldsets), 2)
|
|
|
|
|
self.assertEqual(fieldsets[0][1]['fields'], ['field1'])
|
|
|
|
|
self.assertEqual(fieldsets[1][1]['fields'], ['field3', 'field5'])
|
|
|
|
|
|
|
|
|
|
@override_settings(CUSTOM_MODEL_FIELDS={
|
|
|
|
|
'contrib_dummymodel': {
|
|
|
|
|
'fields': ['field5', 'field3', 'field1']
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
def test_field_order_preservation(self):
|
|
|
|
|
"""Test that field order from settings is preserved"""
|
|
|
|
|
fields = self.admin.get_fields(self.request)
|
|
|
|
|
self.assertEqual(fields, ['field5', 'field3', 'field1'])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_nonexistent_fields(self):
|
|
|
|
|
"""Test behavior with nonexistent fields in settings"""
|
|
|
|
|
with override_settings(CUSTOM_MODEL_FIELDS={
|
|
|
|
|
'contrib_dummymodel': {
|
|
|
|
|
'fields': ['field1', 'nonexistent_field']
|
|
|
|
|
}
|
|
|
|
|
}):
|
|
|
|
|
fields = self.admin.get_fields(self.request)
|
|
|
|
|
self.assertEqual(fields, ['field1', 'nonexistent_field'])
|
|
|
|
|
|
|
|
|
|
def test_nonexistent_exclude(self):
|
|
|
|
|
"""Test behavior with nonexistent fields in settings"""
|
|
|
|
|
with override_settings(CUSTOM_MODEL_FIELDS={
|
|
|
|
|
'contrib_dummymodel': {
|
|
|
|
|
'exclude': ['field1', 'nonexistent', 'field2']
|
|
|
|
|
}
|
|
|
|
|
}):
|
|
|
|
|
fields = self.admin.get_fields(self.request)
|
|
|
|
|
self.assertEqual(fields, ['field3', 'field4', 'field5'])
|
|
|
|
|
|
|
|
|
|
exclude = self.admin.get_exclude(self.request)
|
|
|
|
|
self.assertEqual(set(exclude), {'nonexistent', 'field1', 'field2'})
|
|
|
|
|
|
|
|
|
|
@override_settings(CUSTOM_MODEL_FIELDS={})
|
|
|
|
|
def test_empty_settings(self):
|
|
|
|
|
"""Test behavior with empty settings"""
|
|
|
|
|
fields = self.admin.get_fields(self.request)
|
|
|
|
|
self.assertEqual(fields, ['field1', 'field2', 'field3', 'field4', 'field5'])
|
|
|
|
|
|
|
|
|
|
fieldsets = self.admin.get_fieldsets(self.request)
|
|
|
|
|
self.assertEqual(len(fieldsets), 2)
|
|
|
|
|
self.assertEqual(fieldsets[0][1]['fields'], ['field1', 'field2'])
|
|
|
|
|
self.assertEqual(fieldsets[1][1]['fields'], ['field3', 'field4', 'field5'])
|
|
|
|
|
|
|
|
|
|
@override_settings(CUSTOM_MODEL_FIELDS={
|
|
|
|
|
'contrib_dummymodel': {
|
|
|
|
|
'fields': []
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
def test_empty_included_fields(self):
|
|
|
|
|
"""Test behavior with empty included fields list"""
|
|
|
|
|
fields = self.admin.get_fields(self.request)
|
|
|
|
|
# empty custom fields is perceived as no restriction
|
|
|
|
|
self.assertEqual(fields, ['field1', 'field2', 'field3', 'field4', 'field5'])
|
|
|
|
|
|
|
|
|
|
@override_settings(CUSTOM_MODEL_FIELDS={
|
|
|
|
|
'contrib_dummymodel': {
|
|
|
|
|
'exclude': ['field1', 'field2', 'field3', 'field4', 'field5']
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
def test_exclude_all_fields(self):
|
|
|
|
|
"""Test behavior when all fields are excluded"""
|
|
|
|
|
fields = self.admin.get_fields(self.request)
|
|
|
|
|
self.assertEqual(fields, [])
|
|
|
|
|
|
|
|
|
|
fieldsets = self.admin.get_fieldsets(self.request)
|
|
|
|
|
# as all fields from group2 are excluded, only group1 remains
|
|
|
|
|
self.assertEqual(len(fieldsets), 0)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@override_settings(CUSTOM_MODEL_FIELDS={
|
|
|
|
|
'contrib_dummymodel': {
|
|
|
|
|
'exclude': ['field5']
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
def test_custom_fields_exclude_exclude(self):
|
|
|
|
|
"""Test that custom excluded fields are respected"""
|
|
|
|
|
class OrderedAdmin(DummyAdmin):
|
|
|
|
|
exclude = ['field2', 'field4']
|
|
|
|
|
|
|
|
|
|
admin_instance = OrderedAdmin()
|
|
|
|
|
exclude = admin_instance.get_exclude(self.request)
|
|
|
|
|
# app and custom excludes should be additive
|
|
|
|
|
self.assertEqual(set(exclude), {'field2', 'field4', 'field5'})
|
|
|
|
|
|
|
|
|
|
fields = admin_instance.get_fields(self.request)
|
|
|
|
|
self.assertEqual(fields, ['field1', 'field3'])
|
|
|
|
|
|
|
|
|
|
fieldsets = admin_instance.get_fieldsets(self.request)
|
|
|
|
|
# for fieldsets, the app exclude is irrelevant, thus only field5 is excluded
|
|
|
|
|
self.assertEqual(len(fieldsets), 2)
|
|
|
|
|
self.assertEqual(fieldsets[0][1]['fields'], ['field1', 'field2'])
|
|
|
|
|
self.assertEqual(fieldsets[1][1]['fields'], ['field3', 'field4'])
|
|
|
|
|
|
|
|
|
|
@override_settings(CUSTOM_MODEL_FIELDS={
|
|
|
|
|
'contrib_dummymodel': {
|
|
|
|
|
'exclude': ['field3', 'field4', 'field5']
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
def test_custom_fields_fields_exclude(self):
|
|
|
|
|
"""Test that custom excluded fields are respected"""
|
|
|
|
|
class OrderedAdmin(DummyAdmin):
|
|
|
|
|
fields = ['field1', 'field2', 'field4']
|
|
|
|
|
|
|
|
|
|
admin_instance = OrderedAdmin()
|
|
|
|
|
exclude = admin_instance.get_exclude(self.request)
|
|
|
|
|
self.assertEqual(set(exclude), {'field3', 'field4', 'field5'})
|
|
|
|
|
|
|
|
|
|
fields = admin_instance.get_fields(self.request)
|
|
|
|
|
self.assertEqual(fields, ['field1', 'field2'])
|
|
|
|
|
|
|
|
|
|
fieldsets = admin_instance.get_fieldsets(self.request)
|
|
|
|
|
# as all fields from group2 are excluded, only group1 remains
|
|
|
|
|
self.assertEqual(len(fieldsets), 1)
|
|
|
|
|
self.assertEqual(fieldsets[0][1]['fields'], ['field1', 'field2'])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@override_settings(CUSTOM_MODEL_FIELDS={
|
|
|
|
|
'contrib_dummymodel': {
|
|
|
|
|
'exclude': ['field2', 'field4']
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
def test_combined_admin_and_settings_exclude(self):
|
|
|
|
|
"""Test that both admin and settings excludes are applied while maintaining order"""
|
|
|
|
|
class CombinedAdmin(DummyAdmin):
|
|
|
|
|
fields = ['field5', 'field4', 'field3', 'field2', 'field1']
|
|
|
|
|
exclude = ['field1']
|
|
|
|
|
|
|
|
|
|
admin_instance = CombinedAdmin()
|
|
|
|
|
|
|
|
|
|
fields = admin_instance.get_fields(self.request)
|
|
|
|
|
self.assertEqual(fields, ['field5', 'field3'])
|
|
|
|
|
|
|
|
|
|
exclude = admin_instance.get_exclude(self.request)
|
|
|
|
|
self.assertEqual(set(exclude), {'field1', 'field2', 'field4'})
|
|
|
|
|
|