# -*- coding: utf-8 -*- from django.db import models from django.http import Http404 from django.utils.translation import gettext_lazy as _ from django.db.models import Q # Create your models here. class Comment(models.Model): lang = models.CharField(max_length=5) comment = models.CharField(max_length=100) level = models.CharField(max_length=5) class Log(models.Model): game = models.CharField(max_length=30) date = models.DateField(blank=True, null=True) userinput = models.CharField(max_length=200) iscorrect = models.BooleanField() correct = models.CharField(max_length=200) example = models.CharField(max_length=200,null=True) feedback = models.CharField(max_length=200,null=True) comment = models.CharField(max_length=200) class Semtype(models.Model): semtype = models.CharField(max_length=50) def __unicode__(self): return self.semtype class Source(models.Model): type = models.CharField(max_length=20) name = models.CharField(max_length=20) def __unicode__(self): if self.type and self.name: return "%s: %s" % (self.type, self.name) elif self.name: return "%s" % self.name # First, define the Manager subclass. class NPosManager(models.Manager): def get_query_set(self): return super(NPosManager, self).get_query_set().filter(pos='N') class Dialect(models.Model): dialect = models.CharField(max_length=5) name = models.CharField(max_length=100) def __unicode__(self): if self.dialect and self.name: return "%s: %s" % (self.dialect, self.name) elif self.name: return "%s" % self.name elif self.dialect: return "%s" % self.dialect class MorphPhonTag(models.Model): stem = models.CharField(max_length=20) wordclass = models.CharField(max_length=20) diphthong = models.CharField(max_length=20) gradation = models.CharField(max_length=20) rime = models.CharField(max_length=20) soggi = models.CharField(max_length=20) # diphthong = models.CharField(max_length=20) def __unicode__(self): attrs = [self.stem, self.wordclass, self.diphthong, self.gradation, self.rime, self.soggi] S = unicode('/'.join([a for a in attrs if a.strip()])).encode('utf-8') return S class Meta: unique_together = ("stem", "wordclass", "diphthong", "gradation", "rime", "soggi",) class Word(models.Model): """ >>> a = Word.objects.create(lemma='omg') >>> a.wordnob_set.create(lemma='bbq') """ wordid = models.CharField(max_length=200) language = models.CharField(max_length=5, default='sma') lemma = models.CharField(max_length=200) presentationform = models.CharField(max_length=5) pos = models.CharField(max_length=12) # Accomodate larger PoS stem = models.CharField(max_length=20) wordclass = models.CharField(max_length=8) valency = models.CharField(max_length=10) hid = models.IntegerField(max_length=3, null=True, default=None) semtype = models.ManyToManyField(Semtype) source = models.ManyToManyField(Source) diphthong = models.CharField(max_length=5) gradation = models.CharField(max_length=20) rime = models.CharField(max_length=20) attrsuffix = models.CharField(max_length=20) soggi = models.CharField(max_length=10) compare = models.CharField(max_length=5) frequency = models.CharField(max_length=10) geography = models.CharField(max_length=10) objects = models.Manager() # The default manager. N_objects = NPosManager() # The Noun-specific manager tcomm = models.BooleanField(default=False) # nob = Nob() morphophon = models.ForeignKey(MorphPhonTag, null=True) dialects = models.ManyToManyField(Dialect, null=True) def morphTag(self, nosave=True): try: mphon = self.morphophon except MorphPhonTag.DoesNotExist: mphon = False if not mphon: kwargs = { 'stem': self.stem, 'wordclass': self.wordclass, 'diphthong': self.diphthong, 'gradation': self.gradation, 'rime': self.rime, 'soggi': self.soggi, } morphtag, create = MorphPhonTag.objects.get_or_create(**kwargs) if nosave: return morphtag else: self.morphophon = morphtag self.save() def __init__(self, *args, **kwargs): super(Word, self).__init__(*args, **kwargs) self.definition = self.lemma if self.stem in ['3syll', 'trisyllabic']: self.wordclass = 'Odd' def create(self, *args, **kwargs): morphtag = self.morphTag() self.morphophon = morphtag self.pos = self.pos.lower().capitalize() super(Word, self).create(*args, **kwargs) def save(self, *args, **kwargs): """ Words model has an override to uppercase pos attribute on save, in case data isn't saved properly. """ morphtag = self.morphTag() self.pos = self.pos.lower().capitalize() self.morphophon = morphtag super(Word, self).save(*args, **kwargs) def __unicode__(self): return self.lemma def sem_types_admin(self): return ', '.join([item.semtype for item in self.semtype.order_by('semtype').all()]) def source_admin(self): return ', '.join([item.name for item in self.source.order_by('name').all()]) def translations2(self, target_lang): """ Returns obj.translations2XXX for string """ target_lang = target_lang[-3::] # related = Translations2(target_lang) # return self.__getattribute__(related) return self.wordtranslation_set.filter(language__startswith=target_lang) def baseform(self): """ Returns the infinitive/recitation Form for the Word. V - Inf N - Nom A - Attr Take a look at code in game.BareGame.get_baseform and move that here. """ pos_base = { 'V': 'Inf', 'N': 'Nom', 'A': 'Attr', 'Pron': 'Nom', } try: return self.form_set.filter(tag__string__icontains=pos_base[self.pos])[0] except: return None # TODO: Wordxxx need to be one object # TODO: admin interface is going to have problems loading tons of words, should use search field instead class WordTranslation(models.Model): """ Abstract parent class for all translations. Meta.abstract = True TODO: null=True necessary? """ word = models.ForeignKey(Word) language = models.CharField(max_length=5) wordid = models.CharField(max_length=200) lemma = models.CharField(max_length=200, blank=True) phrase = models.TextField(blank=True) explanation = models.TextField(blank=True) # TODO: pos = models.CharField(max_length=12) pos = models.CharField(max_length=12) semtype = models.ManyToManyField(Semtype) source = models.ManyToManyField(Source) # translations = models.ManyToManyField(Word) frequency = models.CharField(max_length=10) geography = models.CharField(max_length=10) tcomm = models.BooleanField(default=False) tcomm_pref = models.BooleanField(default=False) # TODO: # Need a method here which returns the correct translation string # lemma # lemma (phrase) # lemma (phrase) – explanation def _getTrans(self): if self.lemma: return self.lemma elif self.phrase: return self.phrase elif self.explanation: return self.explanation else: return '' def _getAnswer(self): word_answers = [] if self.lemma: word_answers.append(self.lemma) elif self.phrase: word_answers.append(self.phrase) return word_answers def __unicode__(self): return self._getTrans().encode('utf-8') def __init__(self, *args, **kwargs): super(WordTranslation, self).__init__(*args, **kwargs) self.definition = self._getTrans() self.word_answers = self._getAnswer() # class Meta: # abstract = True # Following are subclassed from above, no need to add anything special. # # class Wordnob(WordTranslation): # class Meta: abstract = True # class Wordswe(WordTranslation): # class Meta: abstract = True # class Wordsme(WordTranslation): # class Meta: abstract = True # class Wordeng(WordTranslation): # class Meta: abstract = True # class Worddeu(WordTranslation): # class Meta: abstract = True class Tagset(models.Model): tagset = models.CharField(max_length=25) def __unicode__(self): return self.tagset def matchFromTagString(self, tag): values = self.tagname_set.all().values_list('tagname', flat=True) tag_matches = [v for v in values if v in tag.string] return tag_matches class Tagname(models.Model): tagname = models.CharField(max_length=25) tagset = models.ForeignKey(Tagset) def __unicode__(self): return self.tagname class Tag(models.Model): string = models.CharField(max_length=25) # TODO: pos = models.CharField(max_length=12) attributive = models.CharField(max_length=5) case = models.CharField(max_length=5) conneg = models.CharField(max_length=5) grade = models.CharField(max_length=10) infinite = models.CharField(max_length=10) mood = models.CharField(max_length=5) number = models.CharField(max_length=5) personnumber = models.CharField(max_length=8) polarity = models.CharField(max_length=5) pos = models.CharField(max_length=12) possessive = models.CharField(max_length=5) subclass = models.CharField(max_length=10) tense = models.CharField(max_length=5) class Admin: pass def __unicode__(self): return self.string attributeFixes = { 'attributive': 'Attributive', 'conneg': 'ConNeg', 'grade': 'Grade', 'infinite': 'Infinite', 'mood': 'Mood', 'number': 'Number', 'personnumber': 'Person-Number', 'polarity': 'Polarity', 'pos': 'Wordclass', 'possessive': 'Possessive', 'subclass': 'Subclass', 'tense': 'Tense', } def repairAttributes(self): """ If data is loaded improperly, certain Form attributes may not be set, such as Form.conneg, Form.personnumber. This function repairs them all, and saves if any repairs are made. It is called as part of __init__ TODO: eventually we want this not to be called, because it increases the query count for each Tag load. """ need_to_save = False error = False for k, v in self.attributeFixes.items(): if not self.__getattribute__(k): try: tags = Tagset.objects.get(tagset=v).matchFromTagString(self) except Tagset.DoesNotExist: error = Http404('Tagset %s does not exist. You may need to reinstall tags.' % v) continue if len(tags) == 1: self.__setattr__(k, tags[0]) need_to_save = True if need_to_save: self.save() if error: raise error def __init__(self, *args, **kwargs): super(Tag, self).__init__(*args, **kwargs) self.repairAttributes() class Form(models.Model): word = models.ForeignKey(Word) tag = models.ForeignKey(Tag) fullform = models.CharField(max_length=200) dialects = models.ManyToManyField(Dialect, null=True) def __unicode__(self): return u'%s' % self.fullform.decode('utf-8') # Testing-- related lookups seem to be quite slow in MySQL...? # return '%s; %s+%s' % (self.fullform, self.word.lemma, self.tag) def matchNumber(self, match): """ Return a form matching the number of another. Must return a type that supports indexing. """ if self.tag.pos not in ['N', 'Adj']: return [self] filter = self.tag.string.replace(self.tag.number, match.tag.number) return self.word.form_set.filter(tag__string=filter) def getBaseform(self, match_num=False): """ Gets the base form (e.g., citation/dictionary form) for the wordform. Nouns -> Nom+Sg, Verbs -> Inf @param match_num: True - If the form supplied is a noun and plural the baseform will be Nominative Plural """ if self.tag.pos in ['N', 'n', 'Pron', 'Num']: if match_num: number = self.tag.number else: number = 'Sg' baseform_num = self.word.form_set.filter(tag__case='Nom') baseform = baseform_num.filter(tag__number=number) if baseform.count() == 0 and number == 'Sg' and baseform_num.count() > 0: baseform = baseform_num elif self.tag.pos in ['V', 'v']: baseform = self.word.form_set.filter(**kwarg) if baseform.count() == 0: baseform = self.word.form_set.filter(tag__personnumber='Sg3') if baseform.count() == 0: raise Form.DoesNotExist elif self.tag.pos in ['A', 'a']: baseform = self.word.form_set.filter(tag__string='A+Pos+Sg+Nom') if baseform.count() == 0: baseform = self.word.form_set.all() if not baseform: raise Form.DoesNotExist else: raise Form.DoesNotExist try: return baseform[0] except IndexError: raise Form.DoesNotExist ############# MORFA FEEDBACK class Feedbackmsg(models.Model): """ XML code for messages in messages.xml """ msgid = models.CharField(max_length=100) def __unicode__(self): return self.msgid class Feedbacktext(models.Model): """ Message text in messages.xml """ message = models.CharField(max_length=200) language = models.CharField(max_length=6) feedbackmsg = models.ForeignKey(Feedbackmsg) def __unicode__(self): attrs = [ self.language, self.message, ] S = unicode('/'.join([a for a in attrs if a.strip()])).encode('utf-8') return self.language + u':' + self.message class Feedback(models.Model): messages = models.ManyToManyField(Feedbackmsg) # TODO: pos = models.CharField(max_length=12) # tag = models.ForeignKey(Tag) # Word morphology / classes attrsuffix = models.CharField(max_length=10,null=True,blank=True) dialects = models.ManyToManyField(Dialect) # diphthong = models.CharField(max_length=5,blank=True,null=True) # gradation = models.CharField(max_length=15,null=True,blank=True) # rime = models.CharField(max_length=20,null=True,blank=True) soggi = models.CharField(max_length=10,null=True,blank=True) stem = models.CharField(max_length=20,blank=True,null=True) wordclass = models.CharField(max_length=20,blank=True,null=True) # Tag / inflection attributive = models.CharField(max_length=10,null=True,blank=True) case2 = models.CharField(max_length=5,null=True,blank=True) grade = models.CharField(max_length=10,null=True,blank=True) mood = models.CharField(max_length=10,null=True,blank=True) number = models.CharField(max_length=5,null=True,blank=True) personnumber = models.CharField(max_length=5,null=True,blank=True) pos = models.CharField(max_length=12,blank=True,null=True) tense = models.CharField(max_length=5,null=True,blank=True) class Meta: # Sma doesn't have "diphthong","gradation" # Sma doesn't have "rime" # unique_together = ("tag") unique_together = ( "pos", "stem", "soggi", "wordclass", "case2", "number", "personnumber", "tense", "mood", "grade", "attrsuffix", "attributive", ) def __unicode__(self): attrs = [ self.stem, self.wordclass, self.pos, self.case2, self.grade, self.mood, self.number, self.personnumber, self.tense, self.attrsuffix, self.attributive, self.soggi ] attrs = [a for a in attrs if a] S = unicode('/'.join([a for a in attrs if a.strip()])).encode('utf-8') return S # def save(self, *args, **kwargs): # """ # Normalize syllables. # """ # syllables = { # '2syll': '2syll', # '3syll': '3syll', # 'bisyllabic': '2syll', # 'trisyllabic': '3syll', # '': '', # } # # if self.stem in syllables.keys(): # self.stem = syllables[self.stem] # # super(Feedback, self).save(*args, **kwargs) ######### EXTRA class Grammarlinks(models.Model): name = models.CharField(max_length=200,blank=True,null=True) address = models.CharField(max_length=800,blank=True,null=True) language = models.CharField(max_length=5,blank=True,null=True)