models.py 8.19 KB
# -*- coding: utf-8 -*-
from django.db.models import Model, CharField, IntegerField, ForeignKey, \
    ManyToManyField, TextField, BooleanField, Manager
from django.utils.translation import ugettext_lazy as _

from common.util import GroupDict
from common.models import NotDeletedManager


class InflectionType(Model):
    symbol = CharField(primary_key=True, max_length=16, db_column='czm')
    color_scheme = IntegerField()
    full_name = CharField(max_length=128)

    def __unicode__(self):
        return self.symbol

    class Meta:
        db_table = 'czescimowy'


class BaseFormLabel(Model):
    symbol = CharField(max_length=32, blank=True, db_column='efobaz')
    inflection_type = ForeignKey(InflectionType)
    index = IntegerField()

    def __unicode__(self):
        return '%s/%s' % (self.symbol, self.inflection_type.symbol)

    class Meta:
        db_table = 'efobazy'
        unique_together = ['symbol', 'inflection_type']
        ordering = ['index']


class DummyEnding(object):
    def __init__(self, string):
        self.index = 0
        self.string = string
        from dictionary.models import Qualifier
        self.qualifiers = Qualifier.objects.none()


class PatternType(Model):
    inflection_type = ForeignKey(
        InflectionType, db_column='czm', verbose_name=_(u'inflection type'))
    # typ wzoru (np. dla rzeczowników: odmiana męska, żeńska lub nijaka)
    symbol = CharField(
        max_length=32, blank=True, db_column='wtyp',
        verbose_name=_(u'pattern type'))
    base_form_labels = ManyToManyField(BaseFormLabel)

    def dummy_base_endings(self):
        bfl_dict = dict(
            (bfl, [DummyEnding(bfl.symbol or self.inflection_type_id)])
            for bfl in self.base_form_labels.all())
        return bfl_dict

    @classmethod
    def options(cls):
        pattern_types = GroupDict()
        for pt in cls.objects.all():
            pattern_types.add(pt.inflection_type_id, (pt.id, unicode(pt)))
        return sorted(pattern_types.items())

    def __unicode__(self):
        return self.symbol.replace('"', "''") or \
            '[%s]' % self.inflection_type_id
        # '%s (%s)' % (self.symbol, self.inflection_type_id)

    class Meta:
        db_table = 'typywzorow'
        ordering = ['symbol']


class Pattern(Model):
    STATUS_NEW = 'nowy'
    STATUS_CONFIRMED = 'conf'
    STATUS_CANDIDATE = 'cand'
    STATUS_CHOICES = (
        (STATUS_NEW, _(u'new')),
        (STATUS_CONFIRMED, _(u'confirmed')),
        (STATUS_CANDIDATE, _(u'candidate')),
    )
    HIDDEN_STATUSES = (STATUS_CANDIDATE, STATUS_NEW)
    name = CharField(
        max_length=32, unique=True, db_column='w_id', verbose_name=_(u'name'))
    old_name = CharField(
        max_length=32, verbose_name=_(u'old name'), null=True)
    type = ForeignKey(
        PatternType, db_column='typ', verbose_name=_(u'type'))
    # rdzeń przykładowej formy hasłowej
    example = CharField(
        max_length=64, db_column='przyklad', verbose_name=_(u'example'),
        blank=True)
    basic_form_ending = CharField(
        max_length=32, db_column='zakp', blank=True,
        verbose_name=_(u'basic form ending'))
    status = CharField(
        max_length=8, choices=STATUS_CHOICES, verbose_name=_(u'status'))
    comment = TextField(
        blank=True, db_column='komentarz', verbose_name=_(u'comment'))
    deleted = BooleanField(default=False)

    objects = NotDeletedManager()
    all_objects = Manager()

    def ending_set(self, subroot='', tag_prefix=None):
        endings = self.endings
        if tag_prefix:
            endings = endings.filter(
                base_form_label__symbol__startswith=tag_prefix)
        return set(subroot + e
                   for e in endings.values_list('string', flat=True))

    def base_endings(self, label_filter=None):
        bfls = self.type.base_form_labels.all()
        endings = Ending.objects.filter(
            base_form_label__patterntype=self.type, pattern=self) \
            .select_related('base_form_label').prefetch_related('qualifiers')
        if label_filter is not None:
            endings = endings.filter(
                base_form_label__symbol__regex=label_filter)
        bfl_dict = GroupDict((bfl, []) for bfl in bfls)
        for ending in endings:
            bfl_dict.add(ending.base_form_label, ending)
        return bfl_dict

    def create_example(self, gender):
        from dictionary.models import Lexeme
        lexemes = Lexeme.objects.filter(
            patterns=self, inflection__gender=gender)
        reader_lexemes = Lexeme.filter_reader(lexemes)
        if reader_lexemes:
            lexeme = reader_lexemes[0]
            PatternExample.objects.create(
                lexeme=lexeme, pattern=self, gender=gender)

    def get_example(self, gender, refresh=False):
        examples = PatternExample.objects.filter(pattern=self, gender=gender)
        if not examples or refresh:
            examples.delete()
            self.create_example(gender)
            examples = PatternExample.objects.filter(
                pattern=self, gender=gender)
        if examples:
            lexeme = examples.get().lexeme
            example_inflections = lexeme.inflection_set.filter(
                pattern=self, gender=gender)
            if example_inflections:
                return lexeme, example_inflections[0].root
            else:
                return self.get_example(gender, refresh=True)

    def is_public(self):
        return self.status not in Pattern.HIDDEN_STATUSES

    def get_root(self, basic_form, gender, use_pattern_ending=False):
        ends = []
        basic_endings = []
        if gender:
            bfl = gender.basic_form_label
            basic_endings = self.endings.filter(base_form_label=bfl)
        elif self.type.inflection_type_id == 'v':
            basic_endings = self.endings.filter(base_form_label__symbol='5')
        elif self.type.inflection_type_id == 'num':
            basic_endings = self.endings.filter(
                base_form_label__symbol__in=('1', '1,z1'))
        else:
            use_pattern_ending = True
        if use_pattern_ending:
            ends.append(self.basic_form_ending)
        else:
            ends += [e.string for e in basic_endings]
        good_ends = [end for end in ends if basic_form.endswith(end)]
        assert len(set(good_ends)) <= 1  # inaczej rdzeń nie jest jednoznaczny
        if good_ends:
            return basic_form[:len(basic_form) - len(good_ends[0])]
        else:
            if not use_pattern_ending:
                return self.get_root(
                    basic_form, gender, use_pattern_ending=True)
            else:
                return None

    def __unicode__(self):
        return self.name

    @staticmethod
    def filter_reader(patterns):
        return patterns.exclude(status__in=Pattern.HIDDEN_STATUSES)

    class Meta:
        db_table = 'wzory'
        ordering = ['name']
        permissions = (
            ('view_pattern', _(u'Can view patterns')),
        )


class PatternNotDeletedManager(Manager):
    use_for_related_field = True

    def get_queryset(self):
        return super(PatternNotDeletedManager, self).get_queryset().filter(
            pattern__deleted=False)


# zakonczenie formy bazowej
class Ending(Model):
    pattern = ForeignKey(Pattern, related_name='endings', db_column='w_id')
    # etykieta (tag) formy bazowej
    base_form_label = ForeignKey(BaseFormLabel, db_column='efobaz')
    # kolejnosc dla zakonczen o tym samym base_form_label
    index = IntegerField(db_column='zind')
    string = CharField(max_length=16, db_column='zak', blank=True)
    qualifiers = ManyToManyField(
        'dictionary.Qualifier', blank=True, db_table='kwalifikatory_zakonczen')

    objects = PatternNotDeletedManager()
    all_objects = Manager()

    def __unicode__(self):
        return '%s : %s : %s' % (
            self.pattern.name, self.string, self.base_form_label)

    class Meta:
        db_table = 'zakonczenia'
        unique_together = ('pattern', 'base_form_label', 'index')
        ordering = ['base_form_label__index', 'index']


class PatternExample(Model):
    pattern = ForeignKey(Pattern)
    gender = ForeignKey('dictionary.Gender')
    lexeme = ForeignKey('dictionary.Lexeme')

    class Meta:
        unique_together = ('pattern', 'gender')
        ordering = ['gender']