diff --git a/src/c3nav/api/migrations/0002_django_4_0.py b/src/c3nav/api/migrations/0002_django_4_0.py new file mode 100644 index 00000000..edb2cb22 --- /dev/null +++ b/src/c3nav/api/migrations/0002_django_4_0.py @@ -0,0 +1,21 @@ +# Generated by Django 4.0.3 on 2022-04-03 17:32 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('api', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='token', + name='user', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/src/c3nav/control/migrations/0009_django_4_0.py b/src/c3nav/control/migrations/0009_django_4_0.py new file mode 100644 index 00000000..6b921f08 --- /dev/null +++ b/src/c3nav/control/migrations/0009_django_4_0.py @@ -0,0 +1,37 @@ +# Generated by Django 4.0.3 on 2022-04-03 17:32 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('mapdata', '0086_django_4_0'), + ('control', '0008_userpermissions_reports'), + ] + + operations = [ + migrations.AlterField( + model_name='userpermissions', + name='review_group_reports', + field=models.ManyToManyField(blank=True, limit_choices_to={'access_restriction': None}, to='mapdata.locationgroup', verbose_name='can review reports belonging to'), + ), + migrations.AlterField( + model_name='userpermissions', + name='user', + field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to=settings.AUTH_USER_MODEL), + ), + migrations.AlterField( + model_name='userspaceaccess', + name='space', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mapdata.space'), + ), + migrations.AlterField( + model_name='userspaceaccess', + name='user', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/src/c3nav/editor/migrations/0002_django_4_0.py b/src/c3nav/editor/migrations/0002_django_4_0.py new file mode 100644 index 00000000..0efa9f7c --- /dev/null +++ b/src/c3nav/editor/migrations/0002_django_4_0.py @@ -0,0 +1,47 @@ +# Generated by Django 4.0.3 on 2022-04-03 17:32 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('contenttypes', '0002_remove_content_type_name'), + ('editor', '0001_squashed_2018'), + ] + + operations = [ + migrations.AlterField( + model_name='changedobject', + name='changeset', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='editor.changeset', verbose_name='Change Set'), + ), + migrations.AlterField( + model_name='changedobject', + name='content_type', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype'), + ), + migrations.AlterField( + model_name='changedobject', + name='m2m_added', + field=models.JSONField(default=dict, verbose_name='added m2m values'), + ), + migrations.AlterField( + model_name='changedobject', + name='m2m_removed', + field=models.JSONField(default=dict, verbose_name='removed m2m values'), + ), + migrations.AlterField( + model_name='changedobject', + name='updated_fields', + field=models.JSONField(default=dict, verbose_name='updated fields'), + ), + migrations.AlterField( + model_name='changeset', + name='author', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL, verbose_name='Author'), + ), + ] diff --git a/src/c3nav/editor/models/changedobject.py b/src/c3nav/editor/models/changedobject.py index bb6e6974..db73cbe4 100644 --- a/src/c3nav/editor/models/changedobject.py +++ b/src/c3nav/editor/models/changedobject.py @@ -9,7 +9,7 @@ from django.db.models import CharField, DecimalField, Field, TextField from django.utils.translation import gettext_lazy as _ from c3nav.editor.wrappers import ModelInstanceWrapper, is_created_pk -from c3nav.mapdata.fields import I18nField, JSONField +from c3nav.mapdata.fields import I18nField from c3nav.mapdata.models.locations import LocationRedirect @@ -35,9 +35,9 @@ class ChangedObject(models.Model): created = models.DateTimeField(auto_now_add=True, verbose_name=_('created')) content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) existing_object_pk = models.PositiveIntegerField(null=True, verbose_name=_('id of existing object')) - updated_fields = JSONField(default={}, verbose_name=_('updated fields')) - m2m_added = JSONField(default={}, verbose_name=_('added m2m values')) - m2m_removed = JSONField(default={}, verbose_name=_('removed m2m values')) + updated_fields = models.JSONField(default=dict, verbose_name=_('updated fields')) + m2m_added = models.JSONField(default=dict, verbose_name=_('added m2m values')) + m2m_removed = models.JSONField(default=dict, verbose_name=_('removed m2m values')) deleted = models.BooleanField(default=False, verbose_name=_('object was deleted')) objects = ChangedObjectManager() diff --git a/src/c3nav/mapdata/fields.py b/src/c3nav/mapdata/fields.py index 59cd7590..19a37fc0 100644 --- a/src/c3nav/mapdata/fields.py +++ b/src/c3nav/mapdata/fields.py @@ -31,7 +31,7 @@ def validate_geometry(geometry: BaseGeometry): shapely_logger = logging.getLogger('shapely.geos') -class GeometryField(models.TextField): +class GeometryField(models.JSONField): default_validators = [validate_geometry] def __init__(self, geomtype=None, default=None, null=False): @@ -50,9 +50,7 @@ class GeometryField(models.TextField): return name, path, args, kwargs def from_db_value(self, value, expression, connection): - if value is None: - return value - return WrappedGeometry(json.loads(value)) + return WrappedGeometry(super().from_db_value(value, expression, connection)) def to_python(self, value): if value is None or value == '': @@ -117,6 +115,7 @@ class GeometryField(models.TextField): class JSONField(models.TextField): + # Deprecated def from_db_value(self, value, expression, connection): if value is None: return value @@ -173,7 +172,7 @@ class I18nDescriptor: setattr(instance, self.field.attname, value) -class I18nField(JSONField): +class I18nField(models.JSONField): def __init__(self, verbose_name=None, plural_name=None, max_length=None, default=None, fallback_language=settings.LANGUAGE_CODE, fallback_any=False, fallback_value=None, **kwargs): self.i18n_max_length = max_length @@ -182,7 +181,7 @@ class I18nField(JSONField): self.fallback_any = fallback_any self.fallback_value = fallback_value kwargs.pop('null', None) - super().__init__(verbose_name=verbose_name, default=(dict(default) if default else {}), null=False, **kwargs) + super().__init__(verbose_name=verbose_name, default=(dict(default) if default else dict), null=False, **kwargs) def get_default(self): return self.default.copy() diff --git a/src/c3nav/mapdata/migrations/0086_django_4_0.py b/src/c3nav/mapdata/migrations/0086_django_4_0.py new file mode 100644 index 00000000..6e264fd3 --- /dev/null +++ b/src/c3nav/mapdata/migrations/0086_django_4_0.py @@ -0,0 +1,316 @@ +# Generated by Django 4.0.3 on 2022-04-03 17:32 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('mapdata', '0085_locationgroupcategory_allow_dynamic_locations'), + ] + + operations = [ + migrations.AlterField( + model_name='accesspermission', + name='access_restriction', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mapdata.accessrestriction'), + ), + migrations.AlterField( + model_name='accesspermission', + name='token', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='mapdata.accesspermissiontoken', verbose_name='Access permission token'), + ), + migrations.AlterField( + model_name='accesspermission', + name='user', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + migrations.AlterField( + model_name='accessrestriction', + name='groups', + field=models.ManyToManyField(blank=True, to='mapdata.accessrestrictiongroup', verbose_name='Groups'), + ), + migrations.AlterField( + model_name='altitudearea', + name='level', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mapdata.level', verbose_name='level'), + ), + migrations.AlterField( + model_name='altitudemarker', + name='space', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mapdata.space', verbose_name='space'), + ), + migrations.AlterField( + model_name='area', + name='access_restriction', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='mapdata.accessrestriction', verbose_name='Access Restriction'), + ), + migrations.AlterField( + model_name='area', + name='groups', + field=models.ManyToManyField(blank=True, to='mapdata.locationgroup', verbose_name='Location Groups'), + ), + migrations.AlterField( + model_name='area', + name='label_settings', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='mapdata.labelsettings', verbose_name='label settings'), + ), + migrations.AlterField( + model_name='area', + name='locationslug_ptr', + field=models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='mapdata.locationslug'), + ), + migrations.AlterField( + model_name='area', + name='space', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mapdata.space', verbose_name='space'), + ), + migrations.AlterField( + model_name='building', + name='level', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mapdata.level', verbose_name='level'), + ), + migrations.AlterField( + model_name='column', + name='access_restriction', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='mapdata.accessrestriction', verbose_name='Access Restriction'), + ), + migrations.AlterField( + model_name='column', + name='space', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mapdata.space', verbose_name='space'), + ), + migrations.AlterField( + model_name='crossdescription', + name='space', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mapdata.space', verbose_name='space'), + ), + migrations.AlterField( + model_name='door', + name='access_restriction', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='mapdata.accessrestriction', verbose_name='Access Restriction'), + ), + migrations.AlterField( + model_name='door', + name='level', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mapdata.level', verbose_name='level'), + ), + migrations.AlterField( + model_name='dynamiclocation', + name='access_restriction', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='mapdata.accessrestriction', verbose_name='Access Restriction'), + ), + migrations.AlterField( + model_name='dynamiclocation', + name='groups', + field=models.ManyToManyField(blank=True, to='mapdata.locationgroup', verbose_name='Location Groups'), + ), + migrations.AlterField( + model_name='dynamiclocation', + name='label_settings', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='mapdata.labelsettings', verbose_name='label settings'), + ), + migrations.AlterField( + model_name='dynamiclocation', + name='locationslug_ptr', + field=models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='mapdata.locationslug'), + ), + migrations.AlterField( + model_name='graphedge', + name='access_restriction', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='mapdata.accessrestriction', verbose_name='Access Restriction'), + ), + migrations.AlterField( + model_name='graphedge', + name='waytype', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='mapdata.waytype', verbose_name='Way Type'), + ), + migrations.AlterField( + model_name='graphnode', + name='space', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mapdata.space', verbose_name='space'), + ), + migrations.AlterField( + model_name='hole', + name='space', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mapdata.space', verbose_name='space'), + ), + migrations.AlterField( + model_name='leavedescription', + name='space', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mapdata.space', verbose_name='space'), + ), + migrations.AlterField( + model_name='level', + name='access_restriction', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='mapdata.accessrestriction', verbose_name='Access Restriction'), + ), + migrations.AlterField( + model_name='level', + name='groups', + field=models.ManyToManyField(blank=True, to='mapdata.locationgroup', verbose_name='Location Groups'), + ), + migrations.AlterField( + model_name='level', + name='label_settings', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='mapdata.labelsettings', verbose_name='label settings'), + ), + migrations.AlterField( + model_name='level', + name='locationslug_ptr', + field=models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='mapdata.locationslug'), + ), + migrations.AlterField( + model_name='lineobstacle', + name='space', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mapdata.space', verbose_name='space'), + ), + migrations.AlterField( + model_name='locationgroup', + name='access_restriction', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='mapdata.accessrestriction', verbose_name='Access Restriction'), + ), + migrations.AlterField( + model_name='locationgroup', + name='label_settings', + field=models.ForeignKey(blank=True, help_text='unless location specifies otherwise', null=True, on_delete=django.db.models.deletion.PROTECT, to='mapdata.labelsettings', verbose_name='label settings'), + ), + migrations.AlterField( + model_name='locationgroup', + name='locationslug_ptr', + field=models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='mapdata.locationslug'), + ), + migrations.AlterField( + model_name='locationredirect', + name='locationslug_ptr', + field=models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='mapdata.locationslug'), + ), + migrations.AlterField( + model_name='mapupdate', + name='user', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL), + ), + migrations.AlterField( + model_name='obstacle', + name='space', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mapdata.space', verbose_name='space'), + ), + migrations.AlterField( + model_name='poi', + name='access_restriction', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='mapdata.accessrestriction', verbose_name='Access Restriction'), + ), + migrations.AlterField( + model_name='poi', + name='groups', + field=models.ManyToManyField(blank=True, to='mapdata.locationgroup', verbose_name='Location Groups'), + ), + migrations.AlterField( + model_name='poi', + name='label_settings', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='mapdata.labelsettings', verbose_name='label settings'), + ), + migrations.AlterField( + model_name='poi', + name='locationslug_ptr', + field=models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='mapdata.locationslug'), + ), + migrations.AlterField( + model_name='poi', + name='space', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mapdata.space', verbose_name='space'), + ), + migrations.AlterField( + model_name='position', + name='coordinates_id', + field=models.CharField(blank=True, max_length=48, null=True, verbose_name='coordinates'), + ), + migrations.AlterField( + model_name='position', + name='owner', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + migrations.AlterField( + model_name='position', + name='timeout', + field=models.PositiveSmallIntegerField(blank=True, default=0, help_text='0 for no timeout', verbose_name='timeout (in seconds)'), + ), + migrations.AlterField( + model_name='ramp', + name='space', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mapdata.space', verbose_name='space'), + ), + migrations.AlterField( + model_name='report', + name='author', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL, verbose_name='author'), + ), + migrations.AlterField( + model_name='report', + name='created_groups', + field=models.ManyToManyField(blank=True, help_text='select all groups that apply, if any', limit_choices_to={'can_report_missing': True}, related_name='+', to='mapdata.locationgroup', verbose_name='location groups'), + ), + migrations.AlterField( + model_name='reportupdate', + name='author', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL, verbose_name='author'), + ), + migrations.AlterField( + model_name='reportupdate', + name='open', + field=models.BooleanField(null=True, verbose_name='open'), + ), + migrations.AlterField( + model_name='source', + name='access_restriction', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='mapdata.accessrestriction', verbose_name='Access Restriction'), + ), + migrations.AlterField( + model_name='space', + name='access_restriction', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='mapdata.accessrestriction', verbose_name='Access Restriction'), + ), + migrations.AlterField( + model_name='space', + name='groups', + field=models.ManyToManyField(blank=True, to='mapdata.locationgroup', verbose_name='Location Groups'), + ), + migrations.AlterField( + model_name='space', + name='label_settings', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='mapdata.labelsettings', verbose_name='label settings'), + ), + migrations.AlterField( + model_name='space', + name='level', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mapdata.level', verbose_name='level'), + ), + migrations.AlterField( + model_name='space', + name='locationslug_ptr', + field=models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='mapdata.locationslug'), + ), + migrations.AlterField( + model_name='stair', + name='space', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mapdata.space', verbose_name='space'), + ), + migrations.AlterField( + model_name='wifimeasurement', + name='author', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='author'), + ), + migrations.AlterField( + model_name='wifimeasurement', + name='data', + field=models.JSONField(verbose_name='Measurement list'), + ), + migrations.AlterField( + model_name='wifimeasurement', + name='space', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mapdata.space', verbose_name='space'), + ), + ] diff --git a/src/c3nav/mapdata/models/geometry/space.py b/src/c3nav/mapdata/models/geometry/space.py index 29263e93..112fadf4 100644 --- a/src/c3nav/mapdata/models/geometry/space.py +++ b/src/c3nav/mapdata/models/geometry/space.py @@ -10,7 +10,7 @@ from django.utils.text import format_lazy from django.utils.translation import gettext_lazy as _ from shapely.geometry import CAP_STYLE, JOIN_STYLE, mapping -from c3nav.mapdata.fields import GeometryField, I18nField, JSONField +from c3nav.mapdata.fields import GeometryField, I18nField from c3nav.mapdata.grid import grid from c3nav.mapdata.models import Space from c3nav.mapdata.models.access import AccessRestrictionMixin @@ -384,7 +384,7 @@ class WifiMeasurement(SpaceGeometryMixin, models.Model): author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True, verbose_name=_('author')) comment = models.TextField(null=True, blank=True, verbose_name=_('comment')) - data = JSONField(_('Measurement list')) + data = models.JSONField(_('Measurement list')) class Meta: verbose_name = _('Wi-Fi Measurement') diff --git a/src/c3nav/routing/migrations/0002_django_4_0.py b/src/c3nav/routing/migrations/0002_django_4_0.py new file mode 100644 index 00000000..d8e775ae --- /dev/null +++ b/src/c3nav/routing/migrations/0002_django_4_0.py @@ -0,0 +1,26 @@ +# Generated by Django 4.0.3 on 2022-04-03 17:32 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('routing', '0001_routeoptions'), + ] + + operations = [ + migrations.AlterField( + model_name='routeoptions', + name='data', + field=models.JSONField(default=dict), + ), + migrations.AlterField( + model_name='routeoptions', + name='user', + field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/src/c3nav/routing/models.py b/src/c3nav/routing/models.py index f66cf910..390e85fb 100644 --- a/src/c3nav/routing/models.py +++ b/src/c3nav/routing/models.py @@ -8,13 +8,12 @@ from django.core.exceptions import ValidationError from django.db import models from django.utils.translation import gettext_lazy as _ -from c3nav.mapdata.fields import JSONField from c3nav.mapdata.models import MapUpdate, WayType class RouteOptions(models.Model): user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, primary_key=True) - data = JSONField(default={}) + data = models.JSONField(default=dict) class Meta: verbose_name = _('Route options') diff --git a/src/c3nav/site/migrations/0006_django_4_0.py b/src/c3nav/site/migrations/0006_django_4_0.py new file mode 100644 index 00000000..5252b2c5 --- /dev/null +++ b/src/c3nav/site/migrations/0006_django_4_0.py @@ -0,0 +1,21 @@ +# Generated by Django 4.0.3 on 2022-04-03 17:32 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('site', '0005_siteupdate_default_related_name'), + ] + + operations = [ + migrations.AlterField( + model_name='announcement', + name='author', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL, verbose_name='author'), + ), + ]