Skip to content

Commit

Permalink
feat: parler poc for Person/name
Browse files Browse the repository at this point in the history
1. modified entity form and filter set for person
2. parler works but migrations are buggy; need to be edited by handel
3. TODO: Data migrations
4. TODO: Postsave signal to save translations/transliterations
automatically
  • Loading branch information
gythaogg committed Nov 16, 2024
1 parent 4da62fb commit d09b906
Show file tree
Hide file tree
Showing 14 changed files with 317 additions and 47 deletions.
11 changes: 11 additions & 0 deletions apis_ontology/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from django.contrib import admin
from parler.admin import TranslatableAdmin

from .models import Person


@admin.register(Person)
class PersonAdmin(TranslatableAdmin):
# TODO: allow editing the translations here?
list_display = ["name", "all_languages_column"]
pass
9 changes: 6 additions & 3 deletions apis_ontology/filtersets.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from django.conf.global_settings import LANGUAGE_CODE
import django_filters
from apis_core.apis_entities.filtersets import (
ABSTRACT_ENTITY_FILTERS_EXCLUDE,
Expand All @@ -9,6 +10,7 @@
from apis_core.relations.models import Relation
from django.apps import apps
from django.db import models
from django.utils.translation import get_language

from apis_ontology.forms import (
PersonSearchForm,
Expand Down Expand Up @@ -212,9 +214,10 @@ class Meta:
)

def custom_name_search(self, queryset, name, value):
name_query = models.Q(name__icontains=value) | models.Q(
alternative_names__icontains=value
)
name_query = models.Q(
translations__name__icontains=value,
translations__language_code=get_language(),
) | models.Q(alternative_names__icontains=value)
if value.isdigit():
name_query = name_query | models.Q(pk=int(value))

Expand Down
8 changes: 5 additions & 3 deletions apis_ontology/forms.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from apis_core.relations.models import Relation
from apis_core.relations.forms import RelationForm
from django import forms
from apis_core.generic.forms import GenericFilterSetForm, GenericModelForm
from django.forms.models import ModelChoiceField
from django.apps import apps
from parler.fields import TranslatedField
from parler.forms import TranslatableModelForm


class TibscholEntityForm(GenericModelForm):
Expand Down Expand Up @@ -35,7 +35,9 @@ class PlaceForm(TibscholEntityForm):
]


class PersonForm(TibscholEntityForm):
class PersonForm(TranslatableModelForm, TibscholEntityForm):
name = TranslatedField()

field_order = [
"name",
"alternative_names",
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# Generated by Django 5.1.3 on 2024-11-15 21:53

import django.db.models.deletion
import parler.fields
import parler.models
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("apis_ontology", "0030_alter_versioninstance_options_and_more"),
]

operations = [
migrations.AlterModelOptions(
name="person",
options={},
),
migrations.AlterModelOptions(
name="versionperson",
options={
"get_latest_by": ("history_date", "history_id"),
"ordering": ("-history_date", "-history_id"),
"verbose_name": "historical person",
"verbose_name_plural": "historical persons",
},
),
migrations.RemoveField(
model_name="person",
name="name",
),
migrations.RemoveField(
model_name="versionperson",
name="name",
),
migrations.AddField(
model_name="person",
name="name_latin",
field=models.CharField(
blank=True,
default="",
editable=False,
max_length=255,
verbose_name="Name",
),
),
migrations.AddField(
model_name="versionperson",
name="name_latin",
field=models.CharField(
blank=True,
default="",
editable=False,
max_length=255,
verbose_name="Name",
),
),
migrations.CreateModel(
name="PersonTranslation",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"language_code",
models.CharField(
db_index=True, max_length=15, verbose_name="Language"
),
),
(
"name",
models.CharField(
blank=True, default="", max_length=255, verbose_name="Name"
),
),
(
"master",
parler.fields.TranslationsForeignKey(
editable=False,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="translations",
to="apis_ontology.person",
),
),
],
options={
"verbose_name": "person Translation",
"db_table": "apis_ontology_person_translation",
"db_tablespace": "",
"managed": True,
"default_permissions": (),
"unique_together": {("language_code", "master")},
},
bases=(parler.models.TranslatableModel, models.Model),
),
migrations.RunSQL(
"INSERT INTO apis_ontology_person_translation(language_code, name , master_id) SELECT 'en', name_latin, rootobject_ptr_id FROM apis_ontology_person;"
),
]
34 changes: 28 additions & 6 deletions apis_ontology/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
from django.urls import reverse
from django.utils.translation import gettext_lazy as _

from parler.models import TranslatableModel, TranslatedFields

from apis_ontology.querysets import PersonQuerySet
from django.utils.translation import get_language

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -69,7 +73,12 @@ def uri(self):


class Person(
VersionMixin, LegacyStuffMixin, LegacyDateMixin, TibScholEntityMixin, AbstractEntity
VersionMixin,
LegacyStuffMixin,
LegacyDateMixin,
TibScholEntityMixin,
AbstractEntity,
TranslatableModel,
):
class_uri = "http://id.loc.gov/ontologies/bibframe/Person"

Expand All @@ -92,18 +101,27 @@ class Person(
]
NATIONALITY = [("Indic", "Indic"), ("Tibetan", "Tibetan")]

name = models.CharField(max_length=255, blank=True, default="", verbose_name="Name")
name_latin = models.CharField(
max_length=255, blank=True, default="", verbose_name="Name", editable=False
)
translations = TranslatedFields(
name=models.CharField(
max_length=255, blank=True, default="", verbose_name="Name"
)
)
gender = models.CharField(max_length=6, choices=GENDERS, default="male")
nationality = models.CharField(
max_length=10, choices=NATIONALITY, blank=True, null=True
)

def __str__(self):
return f"{self.name} ({self.pk})"

class Meta:
verbose_name = _("person")
verbose_name_plural = _("Persons")

def __str__(self):
return f"{self.name} ({self.pk})"
objects = PersonQuerySet.as_manager()


class Place(
Expand Down Expand Up @@ -146,7 +164,9 @@ def with_author(self):
),
# Subquery to get the Person's name based on the person_id from above
author_name=Subquery(
Person.objects.filter(id=OuterRef("author_id")).values("name")[:1]
Person.objects.filter(id=OuterRef("author_id")).values(
"translations__name"
)[:1]
),
)

Expand Down Expand Up @@ -216,7 +236,9 @@ def with_author(self):
),
# Subquery to get the Person's name based on the person_id from above
author_name=Subquery(
Person.objects.filter(id=OuterRef("author_id")).values("name")[:1]
Person.objects.filter(id=OuterRef("author_id")).values(
"translations__name"
)[:1]
),
)

Expand Down
5 changes: 5 additions & 0 deletions apis_ontology/querysets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from parler.managers import TranslatableQuerySet


class PersonQuerySet(TranslatableQuerySet):
pass
51 changes: 51 additions & 0 deletions apis_ontology/settings/server_settings.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import os
from apis_acdhch_default_settings.settings import *
from django.utils.translation import gettext_lazy as _
from django.conf.locale import LANG_INFO

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
Expand All @@ -17,6 +20,7 @@
"apis_core.history",
"django_acdhch_functions",
"django_select2",
"parler",
]
INSTALLED_APPS.remove("apis_ontology")
INSTALLED_APPS.insert(0, "apis_ontology")
Expand Down Expand Up @@ -65,4 +69,51 @@

MIDDLEWARE += [
"simple_history.middleware.HistoryRequestMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.locale.LocaleMiddleware", # Enables language switching based on session
# "apis_ontology.middleware.language_change_middleware.LanguageChangeMiddleware",
]


LANG_INFO.update(
{
"bo": {
"bidi": False, # Set to True if the language is written right-to-left
"code": "bo",
"name": "Tibetan",
"name_local": "བོད་ཡིག", # Native name
},
}
)

LANGUAGE_CODE = "en" # This will be the default language

# Locale paths (optional if you store translations in a custom directory)
# We currently use only model translations on specific fields
# LOCALE_PATHS = [
# BASE_DIR / 'locale',
# ]

PARLER_LANGUAGES = {
None: ( # Site ID 1
{"code": "en"},
{"code": "es"},
),
"default": {
"fallback": "en", # Use English if translation is missing
"hide_untranslated": False, # Show default values for missing translations
},
}


## List of available languages in the app
LANGUAGES = [
("en", _("English")),
("es", _("Tibetan")),
]

LOCALE_PATHS = (os.path.join(BASE_DIR, "apis_ontology", "locale/"),)

USE_I18N = True
USE_L10N = True
USE_TZ = True
17 changes: 17 additions & 0 deletions apis_ontology/signals.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import os
from django.contrib.auth.signals import user_logged_in
from django.db.models.base import post_save
from django.dispatch import receiver
from django.contrib.auth.models import Group
from django.db.models.signals import pre_delete
from apis_core.apis_entities.models import RootObject
from apis_core.relations.models import Relation

from apis_ontology.models import Person, PersonTranslation


@receiver(user_logged_in)
def add_to_group(sender, user, request, **kwargs):
Expand All @@ -19,3 +22,17 @@ def add_to_group(sender, user, request, **kwargs):
def cascade_delete_related(sender, instance, **kwargs):
Relation.objects.filter(subj_object_id=instance.pk).delete()
Relation.objects.filter(obj_object_id=instance.pk).delete()


# post save signal to update translations for person.name
@receiver(post_save, sender=Person)
def update_person_translations(sender, instance, **kwargs):
pass
# TODO: Depending on which language is used while creating objects
# we should create the translation object using pyewts
# if instance.name:
# PersonTranslation.objects.update_or_create(
# master=instance,
# language_code="bo",
# defaults={"name": instance.name},
# )
28 changes: 26 additions & 2 deletions apis_ontology/templates/base.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{% extends "base.html" %}
{% load i18n %}

{% load static %}
{% load tibschol_entity_ctypes %}
Expand Down Expand Up @@ -32,8 +33,31 @@
<a class="dropdown-item" href="{% url 'apis_core:documentation' %}">Data model</a>
</div>
</li>
{{ block.super }}
{% endblock main-menu %}

{{ block.super }}
<ul class="navbar-nav">
<li class="nav-item dropdown-right m-auto">
{% load i18n %}

<form action="{% url 'set_language' %}" method="post">{% csrf_token %}
<input name="next" type="hidden" value="{{ redirect_to }}">
<select name="language">
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}
<option value="en" {% if LANGUAGE_CODE == "en" %}selected {% endif %}>
English
</option>
<option value="es" {% if LANGUAGE_CODE == "es" %}selected {% endif %}>
Tibetan
</option>
</select>
<input type="submit" value="Go">
</form>
</li>
</ul>

{% endblock main-menu %}

{% block modal %}
{{ block.super }}
Expand Down
Loading

0 comments on commit d09b906

Please sign in to comment.