Keep FK & M2M fields pointing to ContentType

This commit is contained in:
Jeremy Stretch 2025-07-25 09:42:38 -04:00
parent 5fe4c96ecf
commit 56955868ce
13 changed files with 28 additions and 107 deletions

View File

@ -18,13 +18,13 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='customfield',
name='object_types',
field=models.ManyToManyField(related_name='custom_fields', to='core.objecttype'),
field=models.ManyToManyField(related_name='custom_fields', to='contenttypes.contenttype'),
),
migrations.AlterField(
model_name='customfield',
name='object_type',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='core.objecttype'
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype'
),
),
migrations.RunSQL((
@ -45,7 +45,7 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='customlink',
name='object_types',
field=models.ManyToManyField(related_name='custom_links', to='core.objecttype'),
field=models.ManyToManyField(related_name='custom_links', to='contenttypes.contenttype'),
),
migrations.RunSQL(
'ALTER TABLE extras_customlink_content_types_id_seq RENAME TO extras_customlink_object_types_id_seq'
@ -59,7 +59,7 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='eventrule',
name='object_types',
field=models.ManyToManyField(related_name='event_rules', to='core.objecttype'),
field=models.ManyToManyField(related_name='event_rules', to='contenttypes.contenttype'),
),
migrations.RunSQL(
'ALTER TABLE extras_eventrule_content_types_id_seq RENAME TO extras_eventrule_object_types_id_seq'
@ -73,7 +73,7 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='exporttemplate',
name='object_types',
field=models.ManyToManyField(related_name='export_templates', to='core.objecttype'),
field=models.ManyToManyField(related_name='export_templates', to='contenttypes.contenttype'),
),
migrations.RunSQL(
'ALTER TABLE extras_exporttemplate_content_types_id_seq RENAME TO extras_exporttemplate_object_types_id_seq'
@ -87,7 +87,7 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='savedfilter',
name='object_types',
field=models.ManyToManyField(related_name='saved_filters', to='core.objecttype'),
field=models.ManyToManyField(related_name='saved_filters', to='contenttypes.contenttype'),
),
migrations.RunSQL(
'ALTER TABLE extras_savedfilter_content_types_id_seq RENAME TO extras_savedfilter_object_types_id_seq'

View File

@ -11,6 +11,6 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='tag',
name='object_types',
field=models.ManyToManyField(blank=True, related_name='+', to='core.objecttype'),
field=models.ManyToManyField(blank=True, related_name='+', to='contenttypes.contenttype'),
),
]

View File

@ -37,7 +37,9 @@ class Migration(migrations.Migration):
(
'object_type',
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, related_name='table_configs', to='core.objecttype'
on_delete=django.db.models.deletion.CASCADE,
related_name='table_configs',
to='contenttypes.contenttype'
),
),
(

View File

@ -1,56 +0,0 @@
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0017_concrete_objecttype'),
('extras', '0130_imageattachment_description'),
]
operations = [
migrations.AlterField(
model_name='Tag',
name='object_types',
field=models.ManyToManyField(blank=True, related_name='+', to='core.objecttype'),
),
migrations.AlterField(
model_name='CustomField',
name='related_object_type',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='core.objecttype'
),
),
migrations.AlterField(
model_name='CustomField',
name='object_types',
field=models.ManyToManyField(related_name='custom_fields', to='core.objecttype'),
),
migrations.AlterField(
model_name='EventRule',
name='object_types',
field=models.ManyToManyField(related_name='event_rules', to='core.objecttype'),
),
migrations.AlterField(
model_name='CustomLink',
name='object_types',
field=models.ManyToManyField(related_name='custom_links', to='core.objecttype'),
),
migrations.AlterField(
model_name='ExportTemplate',
name='object_types',
field=models.ManyToManyField(related_name='export_templates', to='core.objecttype'),
),
migrations.AlterField(
model_name='SavedFilter',
name='object_types',
field=models.ManyToManyField(related_name='saved_filters', to='core.objecttype'),
),
migrations.AlterField(
model_name='TableConfig',
name='object_type',
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, related_name='table_configs', to='core.objecttype'
),
),
]

View File

@ -72,7 +72,7 @@ class CustomFieldManager(models.Manager.from_queryset(RestrictedQuerySet)):
class CustomField(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel):
object_types = models.ManyToManyField(
to='core.ObjectType',
to='contenttypes.ContentType',
related_name='custom_fields',
help_text=_('The object(s) to which this field applies.')
)
@ -84,7 +84,7 @@ class CustomField(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel):
help_text=_('The type of data this custom field holds')
)
related_object_type = models.ForeignKey(
to='core.ObjectType',
to='contenttypes.ContentType',
on_delete=models.PROTECT,
blank=True,
null=True,

View File

@ -49,7 +49,7 @@ class EventRule(CustomFieldsMixin, ExportTemplatesMixin, TagsMixin, ChangeLogged
webhook or executing a custom script.
"""
object_types = models.ManyToManyField(
to='core.ObjectType',
to='contenttypes.ContentType',
related_name='event_rules',
verbose_name=_('object types'),
help_text=_("The object(s) to which this rule applies.")
@ -298,7 +298,7 @@ class CustomLink(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel):
code to be rendered with an object as context.
"""
object_types = models.ManyToManyField(
to='core.ObjectType',
to='contenttypes.ContentType',
related_name='custom_links',
help_text=_('The object type(s) to which this link applies.')
)
@ -394,7 +394,7 @@ class CustomLink(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel):
class ExportTemplate(SyncedDataMixin, CloningMixin, ExportTemplatesMixin, ChangeLoggedModel, RenderTemplateMixin):
object_types = models.ManyToManyField(
to='core.ObjectType',
to='contenttypes.ContentType',
related_name='export_templates',
help_text=_('The object type(s) to which this template applies.')
)
@ -459,7 +459,7 @@ class SavedFilter(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel):
A set of predefined keyword parameters that can be reused to filter for specific objects.
"""
object_types = models.ManyToManyField(
to='core.ObjectType',
to='contenttypes.ContentType',
related_name='saved_filters',
help_text=_('The object type(s) to which this filter applies.')
)
@ -539,7 +539,7 @@ class TableConfig(CloningMixin, ChangeLoggedModel):
A saved configuration of columns and ordering which applies to a specific table.
"""
object_type = models.ForeignKey(
to='core.ObjectType',
to='contenttypes.ContentType',
on_delete=models.CASCADE,
related_name='table_configs',
help_text=_("The table's object type"),

View File

@ -35,7 +35,7 @@ class Tag(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel, TagBase):
blank=True,
)
object_types = models.ManyToManyField(
to='core.ObjectType',
to='contenttypes.ContentType',
related_name='+',
blank=True,
help_text=_("The object type(s) to which this tag can be applied.")

View File

@ -3,7 +3,6 @@ from django.db.models.signals import m2m_changed, post_save, pre_delete
from django.dispatch import receiver
from core.events import *
from core.models import ObjectType
from core.signals import job_end, job_start
from extras.events import process_event_rules
from extras.models import EventRule, Notification, Subscription
@ -82,7 +81,7 @@ def validate_assigned_tags(sender, instance, action, model, pk_set, **kwargs):
"""
if action != 'pre_add':
return
ct = ObjectType.objects.get_for_model(instance)
ct = ContentType.objects.get_for_model(instance)
# Retrieve any applied Tags that are restricted to certain object types
for tag in model.objects.filter(pk__in=pk_set, object_types__isnull=False).prefetch_related('object_types'):
if ct not in tag.object_types.all():

View File

@ -13,6 +13,6 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='objectpermission',
name='object_types',
field=models.ManyToManyField(related_name='object_permissions', to='core.objecttype'),
field=models.ManyToManyField(related_name='object_permissions', to='contenttypes.contenttype'),
),
]

View File

@ -27,6 +27,6 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='objectpermission',
name='object_types',
field=models.ManyToManyField(related_name='object_permissions', to='core.objecttype'),
field=models.ManyToManyField(related_name='object_permissions', to='contenttypes.contenttype'),
),
]

View File

@ -1,17 +0,0 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0017_concrete_objecttype'),
('users', '0009_update_group_perms'),
]
operations = [
migrations.AlterField(
model_name='ObjectPermission',
name='object_types',
field=models.ManyToManyField(related_name='object_permissions', to='core.objecttype'),
),
]

View File

@ -29,7 +29,7 @@ class ObjectPermission(models.Model):
default=True
)
object_types = models.ManyToManyField(
to='core.ObjectType',
to='contenttypes.ContentType',
related_name='object_permissions'
)
actions = ArrayField(

View File

@ -1,19 +1,17 @@
import django_filters
from datetime import datetime, timezone
from itertools import chain
from mptt.models import MPTTModel
import django_filters
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
from django.contrib.contenttypes.models import ContentType
from django.db.models import ForeignKey, ManyToManyField, ManyToManyRel, ManyToOneRel, OneToOneRel
from django.utils.module_loading import import_string
from mptt.models import MPTTModel
from taggit.managers import TaggableManager
from extras.filters import TagFilter
from utilities.filters import ContentTypeFilter, TreeNodeMultipleChoiceFilter
from core.models import ObjectType
__all__ = (
'BaseFilterSetTests',
'ChangeLoggedFilterSetTests',
@ -61,13 +59,6 @@ class BaseFilterSetTests:
if field.related_model is ContentType:
return [(None, None)]
# ForeignKeys to ObjectType need two filters: 'app.model' & PK
if field.related_model is ObjectType:
return [
(filter_name, ContentTypeFilter),
(f'{filter_name}_id', django_filters.ModelMultipleChoiceFilter),
]
# ForeignKey to an MPTT-enabled model
if issubclass(field.related_model, MPTTModel) and field.model is not field.related_model:
return [(f'{filter_name}_id', TreeNodeMultipleChoiceFilter)]
@ -79,8 +70,10 @@ class BaseFilterSetTests:
filter_name = self.get_m2m_filter_name(field)
filter_name = self.filter_name_map.get(filter_name, filter_name)
# ManyToManyFields to ObjectType need two filters: 'app.model' & PK
if field.related_model is ObjectType:
# ManyToManyFields to ContentType need two filters: 'app.model' & PK
if field.related_model is ContentType:
# Standardize on object_type for filter name even though it's technically a ContentType
filter_name = 'object_type'
return [
(filter_name, ContentTypeFilter),
(f'{filter_name}_id', django_filters.ModelMultipleChoiceFilter),