add I18nField and replace the title JSONField with it

This commit is contained in:
Laura Klünder 2017-11-30 00:43:39 +01:00
parent 968fc3885d
commit f94be40470
4 changed files with 174 additions and 18 deletions

View file

@ -2,11 +2,14 @@ import json
import logging import logging
import typing import typing
from django.conf import settings
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator from django.core.validators import RegexValidator
from django.db import models from django.db import models
from django.utils.functional import cached_property from django.utils.functional import cached_property, lazy
from django.utils.text import format_lazy
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils.translation import get_language
from shapely import validation from shapely import validation
from shapely.geometry import LineString, MultiPolygon, Point, Polygon, mapping, shape from shapely.geometry import LineString, MultiPolygon, Point, Polygon, mapping, shape
from shapely.geometry.base import BaseGeometry from shapely.geometry.base import BaseGeometry
@ -126,3 +129,67 @@ class JSONField(models.TextField):
def value_to_string(self, obj): def value_to_string(self, obj):
value = self.value_from_object(obj) value = self.value_from_object(obj)
return self.get_prep_value(value) return self.get_prep_value(value)
def get_i18n_value(i18n_dict, fallback_language, fallback_any, fallback_value):
lang = get_language()
if i18n_dict:
if lang in i18n_dict:
return i18n_dict[lang]
if fallback_language in i18n_dict:
return i18n_dict[fallback_language]
if fallback_any:
return next(iter(i18n_dict.values()))
return str(fallback_value)
lazy_get_i18n_value = lazy(get_i18n_value, str)
class I18nDescriptor:
def __init__(self, field):
self.field = field
def __get__(self, instance, cls=None):
if instance is None:
return self
fallback_value = self.field.fallback_value
if fallback_value is not None:
fallback_value = format_lazy(fallback_value, model_name=instance._meta.verbose_name, pk=instance.pk)
return lazy_get_i18n_value(getattr(instance, self.field.attname),
fallback_language=self.field.fallback_language,
fallback_any=self.field.fallback_any,
fallback_value=fallback_value)
class I18nField(JSONField):
def __init__(self, plural_name=None, fallback_language=settings.LANGUAGE_CODE,
fallback_any=False, fallback_value=None, default=None):
self.plural_name = plural_name
self.fallback_language = fallback_language
self.fallback_any = fallback_any
self.fallback_value = fallback_value
super().__init__(default=(dict(default) if default else {}), null=False)
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
kwargs = {}
if self.default != {}:
kwargs['default'] = self.default
if self.plural_name is not None:
kwargs['plural_name'] = self.plural_name
if self.fallback_language != settings.LANGUAGE_CODE:
kwargs['fallback_language'] = self.fallback_language
if self.fallback_any:
kwargs['fallback_any'] = self.fallback_any
if self.fallback_value is not None:
kwargs['fallback_value'] = self.fallback_value
return name, path, args, kwargs
def contribute_to_class(self, cls, name, *args, **kwargs):
super().contribute_to_class(cls, name, *args, **kwargs)
setattr(cls, self.name, I18nDescriptor(self))
def get_attname(self):
return self.name+'_i18n' if self.plural_name is None else self.plural_name

View file

@ -0,0 +1,104 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-11-29 23:28
from __future__ import unicode_literals
import c3nav.mapdata.fields
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('mapdata', '0052_auto_20171125_1335'),
]
operations = [
migrations.AlterField(
model_name='accessrestriction',
name='titles',
field=c3nav.mapdata.fields.I18nField(fallback_any=True, fallback_value='{model_name} {pk}',
plural_name='titles'),
),
migrations.AlterField(
model_name='area',
name='titles',
field=c3nav.mapdata.fields.I18nField(fallback_any=True, fallback_value='{model_name} {pk}',
plural_name='titles'),
),
migrations.AlterField(
model_name='level',
name='titles',
field=c3nav.mapdata.fields.I18nField(fallback_any=True, fallback_value='{model_name} {pk}',
plural_name='titles'),
),
migrations.AlterField(
model_name='locationgroup',
name='titles',
field=c3nav.mapdata.fields.I18nField(fallback_any=True, fallback_value='{model_name} {pk}',
plural_name='titles'),
),
migrations.AlterField(
model_name='locationgroupcategory',
name='titles',
field=c3nav.mapdata.fields.I18nField(fallback_any=True, fallback_value='{model_name} {pk}',
plural_name='titles'),
),
migrations.AlterField(
model_name='poi',
name='titles',
field=c3nav.mapdata.fields.I18nField(fallback_any=True, fallback_value='{model_name} {pk}',
plural_name='titles'),
),
migrations.AlterField(
model_name='space',
name='titles',
field=c3nav.mapdata.fields.I18nField(fallback_any=True, fallback_value='{model_name} {pk}',
plural_name='titles'),
),
migrations.AlterField(
model_name='waytype',
name='titles',
field=c3nav.mapdata.fields.I18nField(fallback_any=True, fallback_value='{model_name} {pk}',
plural_name='titles'),
),
migrations.RenameField(
model_name='accessrestriction',
old_name='titles',
new_name='title',
),
migrations.RenameField(
model_name='area',
old_name='titles',
new_name='title',
),
migrations.RenameField(
model_name='level',
old_name='titles',
new_name='title',
),
migrations.RenameField(
model_name='locationgroup',
old_name='titles',
new_name='title',
),
migrations.RenameField(
model_name='locationgroupcategory',
old_name='titles',
new_name='title',
),
migrations.RenameField(
model_name='poi',
old_name='titles',
new_name='title',
),
migrations.RenameField(
model_name='space',
old_name='titles',
new_name='title',
),
migrations.RenameField(
model_name='waytype',
old_name='titles',
new_name='title',
),
]

View file

@ -5,7 +5,7 @@ from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils.translation import get_language, get_language_info from django.utils.translation import get_language, get_language_info
from c3nav.mapdata.fields import JSONField from c3nav.mapdata.fields import I18nField
from c3nav.mapdata.models import MapUpdate from c3nav.mapdata.models import MapUpdate
@ -47,7 +47,7 @@ class SerializableMixin(models.Model):
class TitledMixin(SerializableMixin, models.Model): class TitledMixin(SerializableMixin, models.Model):
titles = JSONField(default={}) title = I18nField(plural_name='titles', fallback_any=True, fallback_value='{model_name} {pk}')
class Meta: class Meta:
abstract = True abstract = True
@ -75,15 +75,6 @@ class TitledMixin(SerializableMixin, models.Model):
result['display'].append((language, title)) result['display'].append((language, title))
return result return result
@property
def title(self):
lang = get_language()
if self.titles:
if lang in self.titles:
return self.titles[lang]
return next(iter(self.titles.values()))
return super().title
class BoundsMixin(SerializableMixin, models.Model): class BoundsMixin(SerializableMixin, models.Model):
bottom = models.DecimalField(_('bottom coordinate'), max_digits=6, decimal_places=2) bottom = models.DecimalField(_('bottom coordinate'), max_digits=6, decimal_places=2)

View file

@ -117,12 +117,6 @@ class Location(LocationSlug, AccessRestrictionMixin, TitledMixin, models.Model):
return code+':'+str(self.id) return code+':'+str(self.id)
return self.slug return self.slug
@property
def title(self):
if not self.titles and self.slug:
return self._meta.verbose_name + ' ' + self.slug
return super().title
@property @property
def subtitle(self): def subtitle(self):
return '' return ''