mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-02-22 00:49:35 -06:00
Actually lets remove the old fields
This commit is contained in:
@@ -0,0 +1,117 @@
|
|||||||
|
# Generated by Django 5.2.11 on 2026-02-20 22:05
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
DASHBOARD_VIEWS_VISIBLE_IDS_KEY = (
|
||||||
|
"general-settings:saved-views:dashboard-views-visible-ids"
|
||||||
|
)
|
||||||
|
SIDEBAR_VIEWS_VISIBLE_IDS_KEY = "general-settings:saved-views:sidebar-views-visible-ids"
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_visible_ids(raw_value) -> set[int]:
|
||||||
|
if not isinstance(raw_value, list):
|
||||||
|
return set()
|
||||||
|
|
||||||
|
parsed_ids = set()
|
||||||
|
for raw_id in raw_value:
|
||||||
|
if isinstance(raw_id, int):
|
||||||
|
parsed_ids.add(raw_id)
|
||||||
|
elif isinstance(raw_id, str) and raw_id.isdigit():
|
||||||
|
parsed_ids.add(int(raw_id))
|
||||||
|
return parsed_ids
|
||||||
|
|
||||||
|
|
||||||
|
def _set_default_visibility_ids(apps, schema_editor):
|
||||||
|
SavedView = apps.get_model("documents", "SavedView")
|
||||||
|
UiSettings = apps.get_model("documents", "UiSettings")
|
||||||
|
User = apps.get_model("auth", "User")
|
||||||
|
|
||||||
|
dashboard_visible_ids = list(
|
||||||
|
SavedView.objects.filter(show_on_dashboard=True).values_list("id", flat=True),
|
||||||
|
)
|
||||||
|
sidebar_visible_ids = list(
|
||||||
|
SavedView.objects.filter(show_in_sidebar=True).values_list("id", flat=True),
|
||||||
|
)
|
||||||
|
|
||||||
|
for user in User.objects.all():
|
||||||
|
ui_settings, _ = UiSettings.objects.get_or_create(
|
||||||
|
user=user,
|
||||||
|
defaults={"settings": {}},
|
||||||
|
)
|
||||||
|
current_settings = ui_settings.settings
|
||||||
|
if not isinstance(current_settings, dict):
|
||||||
|
current_settings = {}
|
||||||
|
|
||||||
|
changed = False
|
||||||
|
|
||||||
|
if current_settings.get(DASHBOARD_VIEWS_VISIBLE_IDS_KEY) is None:
|
||||||
|
current_settings[DASHBOARD_VIEWS_VISIBLE_IDS_KEY] = dashboard_visible_ids
|
||||||
|
changed = True
|
||||||
|
if current_settings.get(SIDEBAR_VIEWS_VISIBLE_IDS_KEY) is None:
|
||||||
|
current_settings[SIDEBAR_VIEWS_VISIBLE_IDS_KEY] = sidebar_visible_ids
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
if changed:
|
||||||
|
ui_settings.settings = current_settings
|
||||||
|
ui_settings.save(update_fields=["settings"])
|
||||||
|
|
||||||
|
|
||||||
|
def _restore_visibility_fields(apps, schema_editor):
|
||||||
|
SavedView = apps.get_model("documents", "SavedView")
|
||||||
|
UiSettings = apps.get_model("documents", "UiSettings")
|
||||||
|
|
||||||
|
dashboard_visible_ids = set()
|
||||||
|
sidebar_visible_ids = set()
|
||||||
|
|
||||||
|
for ui_settings in UiSettings.objects.all():
|
||||||
|
current_settings = ui_settings.settings
|
||||||
|
if not isinstance(current_settings, dict):
|
||||||
|
continue
|
||||||
|
dashboard_visible_ids.update(
|
||||||
|
_parse_visible_ids(current_settings.get(DASHBOARD_VIEWS_VISIBLE_IDS_KEY)),
|
||||||
|
)
|
||||||
|
sidebar_visible_ids.update(
|
||||||
|
_parse_visible_ids(current_settings.get(SIDEBAR_VIEWS_VISIBLE_IDS_KEY)),
|
||||||
|
)
|
||||||
|
|
||||||
|
SavedView.objects.update(show_on_dashboard=False, show_in_sidebar=False)
|
||||||
|
if dashboard_visible_ids:
|
||||||
|
SavedView.objects.filter(id__in=dashboard_visible_ids).update(
|
||||||
|
show_on_dashboard=True,
|
||||||
|
)
|
||||||
|
if sidebar_visible_ids:
|
||||||
|
SavedView.objects.filter(id__in=sidebar_visible_ids).update(
|
||||||
|
show_in_sidebar=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("documents", "0011_optimize_integer_field_sizes"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="savedview",
|
||||||
|
name="show_on_dashboard",
|
||||||
|
field=models.BooleanField(default=False, verbose_name="show on dashboard"),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="savedview",
|
||||||
|
name="show_in_sidebar",
|
||||||
|
field=models.BooleanField(default=False, verbose_name="show in sidebar"),
|
||||||
|
),
|
||||||
|
migrations.RunPython(
|
||||||
|
_set_default_visibility_ids,
|
||||||
|
reverse_code=_restore_visibility_fields,
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="savedview",
|
||||||
|
name="show_on_dashboard",
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="savedview",
|
||||||
|
name="show_in_sidebar",
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -443,13 +443,6 @@ class SavedView(ModelWithOwner):
|
|||||||
|
|
||||||
name = models.CharField(_("name"), max_length=128)
|
name = models.CharField(_("name"), max_length=128)
|
||||||
|
|
||||||
show_on_dashboard = models.BooleanField(
|
|
||||||
_("show on dashboard"),
|
|
||||||
)
|
|
||||||
show_in_sidebar = models.BooleanField(
|
|
||||||
_("show in sidebar"),
|
|
||||||
)
|
|
||||||
|
|
||||||
sort_field = models.CharField(
|
sort_field = models.CharField(
|
||||||
_("sort field"),
|
_("sort field"),
|
||||||
max_length=128,
|
max_length=128,
|
||||||
|
|||||||
@@ -1383,8 +1383,6 @@ class SavedViewSerializer(OwnedObjectSerializer):
|
|||||||
fields = [
|
fields = [
|
||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
"show_on_dashboard",
|
|
||||||
"show_in_sidebar",
|
|
||||||
"sort_field",
|
"sort_field",
|
||||||
"sort_reverse",
|
"sort_reverse",
|
||||||
"filter_rules",
|
"filter_rules",
|
||||||
@@ -1416,17 +1414,6 @@ class SavedViewSerializer(OwnedObjectSerializer):
|
|||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
def update(self, instance, validated_data):
|
def update(self, instance, validated_data):
|
||||||
user = getattr(self, "user", None)
|
|
||||||
is_superuser = user.is_superuser if user is not None else False
|
|
||||||
is_owner = instance.owner == user if user is not None else False
|
|
||||||
is_unowned = instance.owner is None
|
|
||||||
if not (is_superuser or is_owner or is_unowned) and (
|
|
||||||
"show_on_dashboard" in validated_data or "show_in_sidebar" in validated_data
|
|
||||||
):
|
|
||||||
raise PermissionDenied(
|
|
||||||
_("Insufficient permissions."),
|
|
||||||
)
|
|
||||||
|
|
||||||
if "filter_rules" in validated_data:
|
if "filter_rules" in validated_data:
|
||||||
rules_data = validated_data.pop("filter_rules")
|
rules_data = validated_data.pop("filter_rules")
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -2027,22 +2027,16 @@ class TestDocumentApi(DirectoriesMixin, DocumentConsumeDelayMixin, APITestCase):
|
|||||||
owner=u1,
|
owner=u1,
|
||||||
name="test1",
|
name="test1",
|
||||||
sort_field="",
|
sort_field="",
|
||||||
show_on_dashboard=False,
|
|
||||||
show_in_sidebar=False,
|
|
||||||
)
|
)
|
||||||
v2 = SavedView.objects.create(
|
v2 = SavedView.objects.create(
|
||||||
owner=u2,
|
owner=u2,
|
||||||
name="test2",
|
name="test2",
|
||||||
sort_field="",
|
sort_field="",
|
||||||
show_on_dashboard=False,
|
|
||||||
show_in_sidebar=False,
|
|
||||||
)
|
)
|
||||||
v3 = SavedView.objects.create(
|
v3 = SavedView.objects.create(
|
||||||
owner=u2,
|
owner=u2,
|
||||||
name="test3",
|
name="test3",
|
||||||
sort_field="",
|
sort_field="",
|
||||||
show_on_dashboard=False,
|
|
||||||
show_in_sidebar=False,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
assign_perm("view_savedview", u1, v2)
|
assign_perm("view_savedview", u1, v2)
|
||||||
@@ -2061,13 +2055,6 @@ class TestDocumentApi(DirectoriesMixin, DocumentConsumeDelayMixin, APITestCase):
|
|||||||
status.HTTP_200_OK,
|
status.HTTP_200_OK,
|
||||||
)
|
)
|
||||||
|
|
||||||
response = self.client.patch(
|
|
||||||
f"/api/saved_views/{v2.id}/",
|
|
||||||
{"show_in_sidebar": True},
|
|
||||||
format="json",
|
|
||||||
)
|
|
||||||
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
|
||||||
|
|
||||||
response = self.client.patch(
|
response = self.client.patch(
|
||||||
f"/api/saved_views/{v2.id}/",
|
f"/api/saved_views/{v2.id}/",
|
||||||
{"sort_field": "added"},
|
{"sort_field": "added"},
|
||||||
@@ -2077,7 +2064,7 @@ class TestDocumentApi(DirectoriesMixin, DocumentConsumeDelayMixin, APITestCase):
|
|||||||
|
|
||||||
response = self.client.patch(
|
response = self.client.patch(
|
||||||
f"/api/saved_views/{v3.id}/",
|
f"/api/saved_views/{v3.id}/",
|
||||||
{"show_in_sidebar": True},
|
{"sort_field": "added"},
|
||||||
format="json",
|
format="json",
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
@@ -2114,8 +2101,6 @@ class TestDocumentApi(DirectoriesMixin, DocumentConsumeDelayMixin, APITestCase):
|
|||||||
|
|
||||||
view = {
|
view = {
|
||||||
"name": "test",
|
"name": "test",
|
||||||
"show_on_dashboard": True,
|
|
||||||
"show_in_sidebar": True,
|
|
||||||
"sort_field": "created2",
|
"sort_field": "created2",
|
||||||
"filter_rules": [{"rule_type": 4, "value": "test"}],
|
"filter_rules": [{"rule_type": 4, "value": "test"}],
|
||||||
}
|
}
|
||||||
@@ -2130,13 +2115,13 @@ class TestDocumentApi(DirectoriesMixin, DocumentConsumeDelayMixin, APITestCase):
|
|||||||
|
|
||||||
response = self.client.patch(
|
response = self.client.patch(
|
||||||
f"/api/saved_views/{v1.id}/",
|
f"/api/saved_views/{v1.id}/",
|
||||||
{"show_in_sidebar": False},
|
{"sort_reverse": True},
|
||||||
format="json",
|
format="json",
|
||||||
)
|
)
|
||||||
|
|
||||||
v1 = SavedView.objects.get(id=v1.id)
|
v1 = SavedView.objects.get(id=v1.id)
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
self.assertFalse(v1.show_in_sidebar)
|
self.assertTrue(v1.sort_reverse)
|
||||||
self.assertEqual(v1.filter_rules.count(), 1)
|
self.assertEqual(v1.filter_rules.count(), 1)
|
||||||
|
|
||||||
view["filter_rules"] = [{"rule_type": 12, "value": "secret"}]
|
view["filter_rules"] = [{"rule_type": 12, "value": "secret"}]
|
||||||
@@ -2170,8 +2155,6 @@ class TestDocumentApi(DirectoriesMixin, DocumentConsumeDelayMixin, APITestCase):
|
|||||||
|
|
||||||
view = {
|
view = {
|
||||||
"name": "test",
|
"name": "test",
|
||||||
"show_on_dashboard": True,
|
|
||||||
"show_in_sidebar": True,
|
|
||||||
"sort_field": "created2",
|
"sort_field": "created2",
|
||||||
"filter_rules": [{"rule_type": 4, "value": "test"}],
|
"filter_rules": [{"rule_type": 4, "value": "test"}],
|
||||||
"page_size": 20,
|
"page_size": 20,
|
||||||
@@ -2259,8 +2242,6 @@ class TestDocumentApi(DirectoriesMixin, DocumentConsumeDelayMixin, APITestCase):
|
|||||||
"""
|
"""
|
||||||
view = {
|
view = {
|
||||||
"name": "test",
|
"name": "test",
|
||||||
"show_on_dashboard": True,
|
|
||||||
"show_in_sidebar": True,
|
|
||||||
"sort_field": "created2",
|
"sort_field": "created2",
|
||||||
"filter_rules": [{"rule_type": 4, "value": "test"}],
|
"filter_rules": [{"rule_type": 4, "value": "test"}],
|
||||||
"page_size": 20,
|
"page_size": 20,
|
||||||
@@ -2336,8 +2317,6 @@ class TestDocumentApi(DirectoriesMixin, DocumentConsumeDelayMixin, APITestCase):
|
|||||||
owner=self.user,
|
owner=self.user,
|
||||||
name="test",
|
name="test",
|
||||||
sort_field=SavedView.DisplayFields.CUSTOM_FIELD % custom_field.id,
|
sort_field=SavedView.DisplayFields.CUSTOM_FIELD % custom_field.id,
|
||||||
show_on_dashboard=True,
|
|
||||||
show_in_sidebar=True,
|
|
||||||
display_fields=[
|
display_fields=[
|
||||||
SavedView.DisplayFields.TITLE,
|
SavedView.DisplayFields.TITLE,
|
||||||
SavedView.DisplayFields.CREATED,
|
SavedView.DisplayFields.CREATED,
|
||||||
|
|||||||
@@ -1309,8 +1309,6 @@ class TestDocumentSearchApi(DirectoriesMixin, APITestCase):
|
|||||||
|
|
||||||
shared_view = SavedView.objects.create(
|
shared_view = SavedView.objects.create(
|
||||||
name="bank view",
|
name="bank view",
|
||||||
show_on_dashboard=True,
|
|
||||||
show_in_sidebar=True,
|
|
||||||
sort_field="",
|
sort_field="",
|
||||||
owner=user2,
|
owner=user2,
|
||||||
)
|
)
|
||||||
|
|||||||
156
src/documents/tests/test_migration_saved_view_visibility.py
Normal file
156
src/documents/tests/test_migration_saved_view_visibility.py
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
from documents.tests.utils import TestMigrations
|
||||||
|
|
||||||
|
DASHBOARD_VIEWS_VISIBLE_IDS_KEY = (
|
||||||
|
"general-settings:saved-views:dashboard-views-visible-ids"
|
||||||
|
)
|
||||||
|
SIDEBAR_VIEWS_VISIBLE_IDS_KEY = "general-settings:saved-views:sidebar-views-visible-ids"
|
||||||
|
|
||||||
|
|
||||||
|
class TestMigrateSavedViewVisibilityToUiSettings(TestMigrations):
|
||||||
|
migrate_from = "0011_optimize_integer_field_sizes"
|
||||||
|
migrate_to = "0012_savedview_visibility_to_ui_settings"
|
||||||
|
|
||||||
|
def setUpBeforeMigration(self, apps) -> None:
|
||||||
|
User = apps.get_model("auth", "User")
|
||||||
|
SavedView = apps.get_model("documents", "SavedView")
|
||||||
|
UiSettings = apps.get_model("documents", "UiSettings")
|
||||||
|
|
||||||
|
self.user_with_empty_settings = User.objects.create(username="user1")
|
||||||
|
self.user_with_existing_settings = User.objects.create(username="user2")
|
||||||
|
self.user_without_settings = User.objects.create(username="user3")
|
||||||
|
self.user_with_empty_settings_id = self.user_with_empty_settings.id
|
||||||
|
self.user_with_existing_settings_id = self.user_with_existing_settings.id
|
||||||
|
self.user_without_settings_id = self.user_without_settings.id
|
||||||
|
|
||||||
|
self.dashboard_view = SavedView.objects.create(
|
||||||
|
owner=self.user_with_empty_settings,
|
||||||
|
name="dashboard",
|
||||||
|
show_on_dashboard=True,
|
||||||
|
show_in_sidebar=True,
|
||||||
|
sort_field="created",
|
||||||
|
)
|
||||||
|
self.sidebar_only_view = SavedView.objects.create(
|
||||||
|
owner=self.user_with_empty_settings,
|
||||||
|
name="sidebar-only",
|
||||||
|
show_on_dashboard=False,
|
||||||
|
show_in_sidebar=True,
|
||||||
|
sort_field="created",
|
||||||
|
)
|
||||||
|
self.hidden_view = SavedView.objects.create(
|
||||||
|
owner=self.user_with_empty_settings,
|
||||||
|
name="hidden",
|
||||||
|
show_on_dashboard=False,
|
||||||
|
show_in_sidebar=False,
|
||||||
|
sort_field="created",
|
||||||
|
)
|
||||||
|
|
||||||
|
UiSettings.objects.create(user=self.user_with_empty_settings, settings={})
|
||||||
|
UiSettings.objects.create(
|
||||||
|
user=self.user_with_existing_settings,
|
||||||
|
settings={
|
||||||
|
DASHBOARD_VIEWS_VISIBLE_IDS_KEY: [self.sidebar_only_view.id],
|
||||||
|
SIDEBAR_VIEWS_VISIBLE_IDS_KEY: [self.dashboard_view.id],
|
||||||
|
"preserve": "value",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_visibility_defaults_are_seeded_and_existing_values_preserved(self) -> None:
|
||||||
|
UiSettings = self.apps.get_model("documents", "UiSettings")
|
||||||
|
|
||||||
|
seeded_settings = UiSettings.objects.get(
|
||||||
|
user_id=self.user_with_empty_settings_id,
|
||||||
|
).settings
|
||||||
|
self.assertCountEqual(
|
||||||
|
seeded_settings[DASHBOARD_VIEWS_VISIBLE_IDS_KEY],
|
||||||
|
[self.dashboard_view.id],
|
||||||
|
)
|
||||||
|
self.assertCountEqual(
|
||||||
|
seeded_settings[SIDEBAR_VIEWS_VISIBLE_IDS_KEY],
|
||||||
|
[self.dashboard_view.id, self.sidebar_only_view.id],
|
||||||
|
)
|
||||||
|
|
||||||
|
existing_settings = UiSettings.objects.get(
|
||||||
|
user_id=self.user_with_existing_settings_id,
|
||||||
|
).settings
|
||||||
|
self.assertEqual(
|
||||||
|
existing_settings[DASHBOARD_VIEWS_VISIBLE_IDS_KEY],
|
||||||
|
[self.sidebar_only_view.id],
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
existing_settings[SIDEBAR_VIEWS_VISIBLE_IDS_KEY],
|
||||||
|
[self.dashboard_view.id],
|
||||||
|
)
|
||||||
|
self.assertEqual(existing_settings["preserve"], "value")
|
||||||
|
|
||||||
|
created_settings = UiSettings.objects.get(
|
||||||
|
user_id=self.user_without_settings_id,
|
||||||
|
).settings
|
||||||
|
self.assertCountEqual(
|
||||||
|
created_settings[DASHBOARD_VIEWS_VISIBLE_IDS_KEY],
|
||||||
|
[self.dashboard_view.id],
|
||||||
|
)
|
||||||
|
self.assertCountEqual(
|
||||||
|
created_settings[SIDEBAR_VIEWS_VISIBLE_IDS_KEY],
|
||||||
|
[self.dashboard_view.id, self.sidebar_only_view.id],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TestReverseMigrateSavedViewVisibilityFromUiSettings(TestMigrations):
|
||||||
|
migrate_from = "0012_savedview_visibility_to_ui_settings"
|
||||||
|
migrate_to = "0011_optimize_integer_field_sizes"
|
||||||
|
|
||||||
|
def setUpBeforeMigration(self, apps) -> None:
|
||||||
|
User = apps.get_model("auth", "User")
|
||||||
|
SavedView = apps.get_model("documents", "SavedView")
|
||||||
|
UiSettings = apps.get_model("documents", "UiSettings")
|
||||||
|
|
||||||
|
user1 = User.objects.create(username="user1")
|
||||||
|
user2 = User.objects.create(username="user2")
|
||||||
|
user3 = User.objects.create(username="user3")
|
||||||
|
|
||||||
|
self.view1 = SavedView.objects.create(
|
||||||
|
owner=user1,
|
||||||
|
name="view-1",
|
||||||
|
sort_field="created",
|
||||||
|
)
|
||||||
|
self.view2 = SavedView.objects.create(
|
||||||
|
owner=user1,
|
||||||
|
name="view-2",
|
||||||
|
sort_field="created",
|
||||||
|
)
|
||||||
|
self.view3 = SavedView.objects.create(
|
||||||
|
owner=user1,
|
||||||
|
name="view-3",
|
||||||
|
sort_field="created",
|
||||||
|
)
|
||||||
|
|
||||||
|
UiSettings.objects.create(
|
||||||
|
user=user1,
|
||||||
|
settings={
|
||||||
|
DASHBOARD_VIEWS_VISIBLE_IDS_KEY: [self.view1.id],
|
||||||
|
SIDEBAR_VIEWS_VISIBLE_IDS_KEY: [self.view2.id],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
UiSettings.objects.create(
|
||||||
|
user=user2,
|
||||||
|
settings={
|
||||||
|
DASHBOARD_VIEWS_VISIBLE_IDS_KEY: [self.view2.id, self.view3.id],
|
||||||
|
SIDEBAR_VIEWS_VISIBLE_IDS_KEY: [],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
UiSettings.objects.create(user=user3, settings={})
|
||||||
|
|
||||||
|
def test_visibility_fields_restored_from_any_user_visibility(self) -> None:
|
||||||
|
SavedView = self.apps.get_model("documents", "SavedView")
|
||||||
|
|
||||||
|
restored_view1 = SavedView.objects.get(pk=self.view1.id)
|
||||||
|
restored_view2 = SavedView.objects.get(pk=self.view2.id)
|
||||||
|
restored_view3 = SavedView.objects.get(pk=self.view3.id)
|
||||||
|
|
||||||
|
self.assertTrue(restored_view1.show_on_dashboard)
|
||||||
|
self.assertTrue(restored_view2.show_on_dashboard)
|
||||||
|
self.assertTrue(restored_view3.show_on_dashboard)
|
||||||
|
|
||||||
|
self.assertFalse(restored_view1.show_in_sidebar)
|
||||||
|
self.assertTrue(restored_view2.show_in_sidebar)
|
||||||
|
self.assertFalse(restored_view3.show_in_sidebar)
|
||||||
@@ -1674,7 +1674,7 @@ class SavedViewViewSet(BulkPermissionMixin, PassUserMixin, ModelViewSet):
|
|||||||
OrderingFilter,
|
OrderingFilter,
|
||||||
ObjectOwnedOrGrantedPermissionsFilter,
|
ObjectOwnedOrGrantedPermissionsFilter,
|
||||||
)
|
)
|
||||||
ordering_fields = ("name", "show_on_dashboard", "show_in_sidebar")
|
ordering_fields = ("name",)
|
||||||
|
|
||||||
|
|
||||||
@extend_schema_view(
|
@extend_schema_view(
|
||||||
|
|||||||
Reference in New Issue
Block a user