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 typing
from django.conf import settings
from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator
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 get_language
from shapely import validation
from shapely.geometry import LineString, MultiPolygon, Point, Polygon, mapping, shape
from shapely.geometry.base import BaseGeometry
@ -126,3 +129,67 @@ class JSONField(models.TextField):
def value_to_string(self, obj):
value = self.value_from_object(obj)
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 get_language, get_language_info
from c3nav.mapdata.fields import JSONField
from c3nav.mapdata.fields import I18nField
from c3nav.mapdata.models import MapUpdate
@ -47,7 +47,7 @@ class 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:
abstract = True
@ -75,15 +75,6 @@ class TitledMixin(SerializableMixin, models.Model):
result['display'].append((language, title))
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):
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 self.slug
@property
def title(self):
if not self.titles and self.slug:
return self._meta.verbose_name + ' ' + self.slug
return super().title
@property
def subtitle(self):
return ''