from random import randint from django import forms from django.conf import settings from django.db.models import OneToOneField, ForeignKey, CharField, ManyToManyField, Q from django.utils.text import format_lazy from django.utils.translation import gettext_lazy as _ from django.utils import translation from crispy_forms.helper import FormHelper import crispy_forms.bootstrap as bootstrap import crispy_forms.layout as layout from connections.models import Entry, POS, Status, SchemaHook from syntax.models import ( Schema, SchemaOpinion, InherentSie, Negativity, Predicativity, Aspect, Position, SyntacticFunction, Control, PredicativeControl, ) from syntax.models_phrase import PhraseTypeModel, PhraseType, EmptyAttributes, XPAttributes, AdvPAttributes, ComparAttributes, FixedAttributes, LemmaOperator, LemmaCooccur, Lemma from semantics.models import ( Frame, FrameOpinion, Argument, SemanticRole, RoleAttribute, PredefinedSelectionalPreference, RelationalSelectionalPreference, SelectionalPreferenceRelation, ) from meanings.models import Synset from unifier.models import UnifiedFrame from .form_fields.generic_fields import ( RangeFilter, RegexFilter, ChoiceFilter, ModelChoiceFilter, MultipleChoiceFilter, ModelMultipleChoiceFilter, OperatorField, SwitchField, ) from .form_fields.specialised_fields import ( PhraseoFilter, PhraseTypeFilter, RoleNameFilter, RoleAttributeFilter, ) from .form_fields.query_managers import SingleValueQueryManager # TODO better to import this from the importer, the web app should not be aware of the importer! :) from importer.PhraseAttributes import attrs_helpers from . import polish_strings class QueryForm(forms.Form): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.helper = FormHelper() self.helper.form_class = 'form-horizontal' self.helper.label_class = 'col-sm-2' self.helper.field_class = 'col-sm-10' self.helper.attrs = { 'data_formtype' : 'unknown' } @staticmethod def get_child_form_prefix(child_form): print(type(child_form)) raise NotImplementedError def get_queries(self, negated_attrs): queries = [] for key, value in self.cleaned_data.items(): #print('========', key, value) if value and not key.startswith('filter') and not key.startswith('negate'): form_field = self.fields[key] if hasattr(form_field, 'query_manager'): conjunction = form_field.query_manager.default_conjunction negate = key in negated_attrs qs = form_field.query_manager.make_queries(value, conjunction) assert(len(qs) < 2) queries += [~q if negate else q for q in qs] return queries def is_negated(self): for key, value in self.cleaned_data.items(): if key.startswith('negate') and value: return True return False @classmethod def make_field(cls, field_name): field_object = cls.base_fields[field_name] return field_object.layout(field_name) def or_button(button_label, add_button_id): return bootstrap.StrictButton('+ {} ({})'.format(_('Lub'), button_label), css_class='or-button btn-xs btn-info', data_add_id=add_button_id) def other_button(button_label, add_button_id): return bootstrap.StrictButton('+ {} ({})'.format(_('Inny'), button_label), css_class='other-button btn-xs btn-warning', data_add_id=add_button_id) def and_or_form_creator(button_label, button_id, field=None, data_add=None, add_other=False, help=None, tooltip=None, *args, **kwargs): add_button = None data_add = 'switch' if data_add is None else data_add if field is not None: add_button = bootstrap.FieldWithButtons(field, bootstrap.StrictButton('+ {}'.format(_('Dodaj')), css_id=button_id, css_class='add-button btn-xs btn-success', data_add=data_add, *args, **kwargs)) else: add_button = bootstrap.StrictButton('+ {}'.format(button_label), css_id=button_id, css_class='add-button btn-xs btn-success', data_add=data_add, *args, **kwargs) ret = [ layout.HTML('<div class="and-or-forms py-1" data-formtype="{}">'.format(data_add)), add_button, or_button(button_label, button_id), layout.HTML('</div>'), ] if add_other: ret.insert(-1, other_button(button_label, button_id)) if help: help_tooltip = '' if tooltip: help_tooltip = f' <span data-toggle="tooltip" data-placement="bottom" title="{tooltip}"><img src="{settings.STATIC_URL}common/img/info.svg" alt="info" width="12" height="12"/></span>' ret.insert(-1, layout.HTML('<small class="form-text text-muted">{}{}</small>'.format(help, help_tooltip))) return ret class EntryForm(QueryForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) #self.helper.form_method = 'get' # TODO remove if this form is to be used with different views self.helper.form_action = 'entries:get_entries' self.helper.form_id = 'main-form' self.helper.attrs = { 'data_formtype' : 'entry' } self.model_class = Entry entry_components = [ self.make_field('lemma'), self.make_field('pos'), self.make_field('phraseology'), self.make_field('status'), ] schema_components = [ self.make_field('num_schemata'), ] + \ and_or_form_creator(_('Schemat'), 'add-schema-0', data_add='schema', add_other=True, help=_('Schemat(y) występujące w haśle')) + \ and_or_form_creator(_('Pozycja'), 'add-position-0', data_add='position', add_other=True, help=_('Pozycja/e występujące w haśle'), tooltip=_('Pozycje mogą występować w różnych schematach. Aby ograniczyć filtrowanie do występowania wymaganych pozycji w obrębie jednego schematu, proszę użyć filtru POZYCJA wewnątrz filtra SCHEMAT powyżej.') ) + \ and_or_form_creator(_('Fraza'), 'add-phrase-0', field=self.make_field('phrase_type'), data_prefix='phrase_', help=_('Fraza/y występujące w haśle'), tooltip=_('Frazy mogą występować w różnych schematach i na różnych pozycjach. Aby ograniczyć filtrowanie do występowania wymaganych fraz w obrębie jednej pozycji, proszę użyć filtru POZYCJA powyżej lub wewnątrz filtra SCHEMAT.') ) + \ [ self.make_field('filter_schemata'), ] frame_components = [ self.make_field('num_frames'), ] + \ and_or_form_creator(_('Rama'), 'add-frame-0', data_add='frame', add_other=True, help=_('Rama/y występujące w haśle')) + \ and_or_form_creator(_('Argument'), 'add-argument-0', data_add='argument', help=_('Argument(y) występujące w haśle')) + \ [ self.make_field('filter_frames'), ] components = [ layout.Fieldset(_('Własności hasła'), *entry_components), layout.Fieldset(_('Własności składniowe'), *schema_components), layout.Fieldset(_('Własności semantyczne'), *frame_components), layout.Submit('main-submit', _('Filtruj'), css_class='btn-sm'), layout.Reset('main-reset', _('Wyczyść'), css_class='btn-sm'), ] self.helper.layout = layout.Layout(*components) lemma = RegexFilter( label=_('Lemat'), lookup='name', max_length=200, autocomplete='lemma', ) pos = ModelMultipleChoiceFilter( label=_('Część mowy'), queryset=POS.objects.exclude(tag='unk'), key='tag', human_values=polish_strings.POS(), lookup='pos', ) phraseology = PhraseoFilter() status = ModelMultipleChoiceFilter( label ='Status', queryset=Status.objects.all().order_by('-priority'), key = 'key', human_values=polish_strings.STATUS(), lookup='status', ) num_schemata = RangeFilter( label=_('Liczba schematów'), lookup='schemata_count', ) num_frames = RangeFilter( label=_('Liczba ram'), lookup='frames_count', ) phrase_type = PhraseTypeFilter( queryset=PhraseTypeModel.objects.filter(main_phrase_types__positions__schemata__isnull=False).distinct(), #help_text=_('Typ frazy występujący w haśle.'), ) filter_schemata = SwitchField(_('Ukryj niepasujące schematy')) filter_frames = SwitchField(_('Ukryj niepasujące ramy')) @staticmethod def get_child_form_prefix(child_form): if child_form.model_class == Schema: return 'subentries__schemata__in' if child_form.model_class == Position: return 'subentries__schemata__positions__in' if child_form.model_class == PhraseType: return 'subentries__schemata__positions__phrase_types__in' if child_form.model_class == Frame: return 'subentries__schema_hooks__argument_connections__argument__frame__in' if child_form.model_class == Argument: return 'subentries__schema_hooks__argument_connections__argument__in' raise KeyError(type(child_form)) # for forms that can appear multiple times in the query constructor field # (e.g. a phrase form), create a separate form class for each form ‘instance’, # with globally unique field names to ensure proper javascript behaviour # and retrieving the field values in views class FormFactory(object): form_class_name = None form_model = None form_formtype = None form_header = None @staticmethod def unique_number(): return randint(1000, 12345678) @staticmethod def unique_name(field_name, unique_number): return '{}_{}'.format(field_name, unique_number) @staticmethod def make_helper_attrs(form_type, unique_number): return { 'data_formtype' : form_type , 'data_formnumber' : unique_number } @staticmethod def make_layout(title, components, as_subform=True): elements = [] if as_subform: elements.append('{} <span class="collapsed-info text-info"></span> <button class="btn collapse-button btn-xs btn-secondary" data-collapsed="false" type="button">{}</button><button class="btn remove-button btn-xs btn-danger" type="button">{}</button>'.format(title, _('Zwiń'), _('Usuń'))) elements += components if not as_subform: elements += [ layout.Submit('main-submit', _('Filtruj'), css_class='btn-sm'), layout.Reset('main-reset', _('Wyczyść'), css_class='btn-sm'), ] return layout.Layout(layout.Fieldset( *elements )) @staticmethod def additional_queries(): return [] @classmethod def get_form(cls, unique_number=None, as_subform=True, *args, **kwargs): unique_number = cls.unique_number() if unique_number is None else unique_number assert(cls.form_class_name is not None) assert(cls.form_model is not None) assert(cls.form_formtype is not None) assert(cls.form_header is not None) form_class = type(cls.form_class_name, (QueryForm,), { #'__init__' : form_init, 'get_child_form_prefix' : lambda self, child_form: cls.get_child_form_prefix(child_form), }) def form_init(self, *args, **kwargs): super(type(self), self).__init__(*args, **kwargs) self.helper.attrs = cls.make_helper_attrs(cls.form_formtype, unique_number) self.model_class = cls.form_model components = [self.make_field(cls.unique_name('negated', unique_number))] for field_name, field_maker, component_maker in cls.field_makers: if component_maker: component = component_maker(unique_number, form_class) else: component = self.make_field(cls.unique_name(field_name, unique_number)) if type(component) == list: components += component else: components.append(component) self.helper.layout = cls.make_layout(cls.form_header, components, as_subform=as_subform) form_class.__init__ = form_init def get_queries(self, negated_attrs): return super(type(self), self).get_queries(negated_attrs) + cls.additional_queries() form_class.get_queries = get_queries form_class.base_fields[cls.unique_name('negated', unique_number)] = SwitchField(_('Zaneguj'), css_class='negate-switch') for field_name, field_maker, layout_maker in cls.field_makers: if field_name is not None: form_class.base_fields[FormFactory.unique_name(field_name, unique_number)] = field_maker() return form_class(*args, **kwargs) @staticmethod def get_child_form_prefix(child_form): raise NotImplementedError class SchemaFormFactory(FormFactory): form_class_name = 'SchemaForm' form_model = Schema form_formtype = 'schema' form_header = _('Schemat składniowy') field_makers = ( ( 'opinion', lambda: ModelMultipleChoiceFilter( label=_('Opinia o schemacie'), queryset=SchemaOpinion.objects.filter(schemata__isnull=False).distinct(), key='key', human_values=polish_strings.SCHEMA_OPINION(), lookup='opinion', ), None, ), ( 'type', lambda: MultipleChoiceFilter( label=_('Typ'), choices=( (False, (_('zwykły'), None)), (True, (_('frazeologiczny'), None)), ), lookup='phraseologic', ), None, ), ( 'sie', lambda: ModelMultipleChoiceFilter( label=_('Zwrotność'), queryset=InherentSie.objects.all(), key='name', human_values=polish_strings.TRUE_FALSE_YES_NO, lookup='subentries__inherent_sie', ), None, ), ( 'neg', lambda: ModelMultipleChoiceFilter( label=_('Negatywność'), queryset=Negativity.objects.exclude(name=''), key='name', human_values=polish_strings.NEGATION(), lookup='subentries__negativity', ), None, ), ( 'pred', lambda: ModelMultipleChoiceFilter( label=_('Predykatywność'), queryset=Predicativity.objects.all(), key='name', human_values=polish_strings.TRUE_FALSE_YES_NO, lookup='subentries__predicativity', ), None, ), ( 'aspect', lambda: ModelMultipleChoiceFilter( label=_('Aspekt'), queryset=Aspect.objects.exclude(name='').exclude(name='_'), key='name', human_values=polish_strings.ASPECT(), lookup='subentries__aspect', ), None, ), #phrase = RegexFilter( #label='Fraza', #max_length=200, ##initial='np.* !& !np.* | xp.*', #lookup='positions__phrase_types__text_rep', #additional_operators=True, #autocomplete='phrasetype', #) ( 'num_positions', lambda: RangeFilter( label=_('Liczba pozycyj'), lookup='positions_count', ), None, ), #( # 'num_phrase_types', # lambda: RangeFilter( # label='Liczba typów fraz w pozycji', # entry_lookup='subentries__schemata__positions__phrases_count', # object_lookup='positions__phrases_count', # ) #), ( None, None, lambda n, cls: and_or_form_creator(_('Pozycja'), 'add-position-{}'.format(n), data_add='position', add_other=True, help=_('Pozycja/e występujące w schemacie')), ), ) @staticmethod def get_child_form_prefix(child_form): if child_form.model_class == Position: return 'positions__in' raise KeyError(type(child_form)) class PositionFormFactory(FormFactory): form_class_name = 'PositionForm' form_model = Position form_formtype = 'position' form_header = _('Pozycja składniowa') field_makers = ( ( 'gram_function', lambda: ModelMultipleChoiceFilter( label=_('Funkcja gramatyczna'), queryset=SyntacticFunction.objects.all(), key='name', human_values=polish_strings.GRAM_FUNCTION(), lookup='function', ), None, ), ( 'control', lambda: ModelMultipleChoiceFilter( label=_('Kontrola'), queryset=Control.objects.filter(positions__isnull=False).distinct(), key='name', human_values=polish_strings.CONTROL(), lookup='control', ), None, ), ( 'pred_control', lambda: ModelMultipleChoiceFilter( label=_('Kontrola predykatywna'), queryset=PredicativeControl.objects.all(), key='name', human_values=polish_strings.CONTROL(), lookup='pred_control', ), None, ), ( 'num_phrases', lambda: RangeFilter( label=_('Liczba fraz'), lookup='phrases_count', ), None, ), ( 'phrase_type', #lambda: PhraseTypeFilter(help_text=_('Typ frazy występujący na pozycji.')), lambda: PhraseTypeFilter(), lambda n, cls: and_or_form_creator(_('Fraza'), 'add-phrase-{}'.format(n), field=cls.make_field(FormFactory.unique_name('phrase_type', n)), data_prefix='phrase_', help=_('Fraza/y występujące na pozycji')), ), ) @staticmethod def get_child_form_prefix(child_form): if child_form.model_class == PhraseType: return 'phrase_types__in' raise KeyError(type(child_form)) class LemmaFormFactory(FormFactory): form_class_name = 'LemmaForm' form_model = Lemma form_formtype = 'lemma' form_header = _('Lemat') field_makers = ( ( 'lemma', lambda: RegexFilter( label=_('Lemat'), max_length=32, lookup='name', autocomplete='lex_lemma' ), None, ), ) class LexFormFactory(FormFactory): form_class_name = 'LexForm' form_model = PhraseType form_formtype = 'phrase_lex' form_header = _('Fraza zleksykalizowana') field_makers = ( ( 'lemma_operator', lambda: ModelMultipleChoiceFilter( label=_('Wybór lematów'), queryset=LemmaOperator.objects.all(), key='name', human_values=polish_strings.LEMMA_OPERATOR(), lookup='lemma_operator', ), None, ), ( 'lemma_cooccur', lambda: ModelMultipleChoiceFilter( label=_('Łączenie lematów'), queryset=LemmaCooccur.objects.all(), key='name', human_values=polish_strings.LEMMA_COOCCUR(), lookup='lemma_cooccur', ), None, ), ( None, None, lambda n, cls: and_or_form_creator(_('Lemat'), 'add-lemma-{}'.format(n), data_add='lemma'), ), ( 'lex_type', lambda: PhraseTypeFilter(lex=True, help_text=_('Typ składniowy frazy zleksykalizowanej.')), lambda n, cls: and_or_form_creator(_('Typ frazy'), 'add-lex-{}'.format(n), field=cls.make_field(FormFactory.unique_name('lex_type', n)), data_prefix='phrase_lex') ), ) @staticmethod def additional_queries(): return [Q(('main_type__name', 'lex'))] @staticmethod def get_child_form_prefix(child_form): if child_form.model_class == PhraseType: return 'id__in' if child_form.model_class == Lemma: return 'lemmata__in' raise KeyError(type(child_form)) class FrameFormFactory(FormFactory): form_class_name = 'FrameForm' form_model = Frame form_formtype = 'frame' form_header = _('Rama semantyczna') field_makers = ( ( 'opinion', lambda: ModelMultipleChoiceFilter( label=_('Opinia'), queryset=FrameOpinion.objects.exclude(key='unk').filter(frame__isnull=False).distinct(), key='key', human_values=polish_strings.FRAME_OPINION(), lookup='opinion', ), None, ), ( 'num_arguments', lambda: RangeFilter( label=_('Liczba argumentów'), lookup='arguments_count', ), None ), ( None, None, lambda n, cls: and_or_form_creator(_('Argument'), 'add-argument-{}'.format(n), data_add='argument'), ), ) @staticmethod def get_child_form_prefix(child_form): if child_form.model_class == Argument: return 'arguments__in' raise KeyError(type(child_form)) class UnifiedFrameFormFactory(FormFactory): form_class_name = 'UnifiedFrameForm' form_model = UnifiedFrame form_formtype = 'unifiedframe' form_header = _('Zunifikowana rama semantyczna') field_makers = ( ( 'opinion', lambda: ModelMultipleChoiceFilter( label=_('Opinia'), queryset=FrameOpinion.objects.exclude(key='unk').filter(frame__isnull=False).distinct(), key='key', human_values=polish_strings.FRAME_OPINION(), lookup='opinion', ), None, ), ( 'num_arguments', lambda: RangeFilter( label=_('Liczba argumentów'), lookup='arguments_count', ), None ), ( 'num_frames', lambda: RangeFilter( label=_('Liczba ram semantycznych'), lookup='slowal_frames_count', ), None ), ( 'name', lambda: RegexFilter( label=_('Nazwa'), max_length=200, lookup='title', ), None, ), ( 'lemmas', lambda: RegexFilter( label=_('Lematy jednostek leksykalnych'), max_length=200, lookup='unified_frame_2_slowal_frame__slowal_frame__lexical_units__base', ), None, ), ( None, None, lambda n, cls: and_or_form_creator(_('UnifiedFrameArgument'), 'add-argument-{}'.format(n), data_add='argument'), ), ) @staticmethod def get_child_form_prefix(child_form): if child_form.model_class == Argument: return 'arguments__in' raise KeyError(type(child_form)) class ArgumentFormFactory(FormFactory): form_class_name = 'ArgumentForm' form_model = Argument form_formtype = 'argument' form_header = _('Argument semantyczny') field_makers = ( ( 'role', lambda: RoleNameFilter( label=_('Rola'), lookup='role__role', ), None, ), ( 'role_attribute', lambda: RoleAttributeFilter( label=_('Atrybut roli'), lookup='role__attribute', ), None, ), ( 'num_preferences', lambda: RangeFilter( label=_('Liczba preferencyj selekcyjnych argumentu'), lookup='preferences_count', ), None ), ( 'preference_type', lambda: ChoiceFilter( label=_('Preferencja selekcyjna'), choices=(('', _('wybierz')), ('predefined', _('Predefiniowana grupa znaczeń')), ('relational', _('Wyrażona przez relację')), ('synset', _('Wyrażona przez jednostkę leksykalną Słowosieci'))), ), lambda n, cls: and_or_form_creator(_('Preferencja selekcyjna'), 'add-preference-{}'.format(n), field=cls.make_field(FormFactory.unique_name('preference_type', n))) ), # removing until we discuss whether this field is needed & how it should work #( # None, None, # lambda n, cls: and_or_form_creator(_('Pozycja'), 'add-position-{}'.format(n), data_add='position'), #), ( 'phrase_type', lambda: PhraseTypeFilter(help_text=_('Typ frazy, przez którą może być realizowany argument.')), lambda n, cls: and_or_form_creator(_('Fraza'), 'add-phrase-{}'.format(n), field=cls.make_field(FormFactory.unique_name('phrase_type', n)), data_prefix='phrase_'), ), ) @staticmethod def get_child_form_prefix(child_form): if child_form.model_class == PredefinedSelectionalPreference: return 'predefined__in' if child_form.model_class == RelationalSelectionalPreference: return 'relations__in' if child_form.model_class == Synset: return 'synsets__in' if child_form.model_class == PhraseType: return 'argument_connections__schema_connections__phrase_type__in' raise KeyError(type(child_form)) class PredefinedPreferenceFormFactory(FormFactory): form_class_name = 'PredefinedPreferenceForm' form_model = PredefinedSelectionalPreference form_formtype = 'predefined' form_header = _('Preferencja predefiniowana') field_makers = ( ( 'predefined', lambda: ModelMultipleChoiceFilter( label=_('Predefiniowane'), queryset=PredefinedSelectionalPreference.objects.all(), key='key', lookup='key', ), None, ), ) class RelationalPreferenceFormFactory(FormFactory): form_class_name = 'RelationalPreferenceForm' form_model = RelationalSelectionalPreference form_formtype = 'relational' form_header = _('Preferencja – relacja') field_makers = ( ( 'relation', lambda: ModelMultipleChoiceFilter( label=_('Relacja'), queryset=SelectionalPreferenceRelation.objects.all(), key='key', human_values=polish_strings.RELATION(), lookup='relation', checkboxes=False, ), None, ), ( 'to_role', lambda: RoleNameFilter( label=_('Do: rola'), lookup='to__role__role', ), None, ), ( 'to_attribute', lambda: RoleAttributeFilter( label=_('Do: atrybut'), lookup='to__role__attribute', ), None, ) ) class SynsetPreferenceFormFactory(FormFactory): form_class_name = 'SynsetPreferenceForm' form_model = Synset form_formtype = 'synset' form_header = _('Preferencja – Słowosieć') field_makers = ( ( 'synset', lambda: RegexFilter( label=_('Jednostka leksykalna'), max_length=200, lookup='lexical_units__text_rep', autocomplete='lu' ), None, ), ) class PhraseAttributesFormFactory(FormFactory): # field types are dynamic here field_makers = None @classmethod def make_form_class(cls, n, model, lex_model, phrase_type): #print('*****************', n, model, lex_model, phrase_type) lex_phrase = lex_model is not None fields = list(filter(lambda x: type(x) in (OneToOneField, ForeignKey, CharField, ManyToManyField) and not x.name.endswith('_ptr'), model._meta.get_fields())) if lex_phrase: lex_fields = list(filter(lambda x: type(x) in (OneToOneField, ForeignKey, CharField, ManyToManyField) and not x.name.endswith('_ptr'), lex_model._meta.get_fields())) else: lex_fields = [] all_fields = [(f, '{}'.format(f.name)) for f in fields] + [(f, 'lex_{}'.format(f.name)) for f in lex_fields] class AttributesForm(QueryForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.helper.attrs = cls.make_helper_attrs('phrase_{}{}'.format('lex' if lex_model else '', phrase_type), n) self.helper.form_id = 'phrase-form' self.model_class = PhraseType components = [self.make_field(cls.unique_name('negated', n))] for field, name in all_fields: uniq_name = cls.unique_name(name, n) if name == 'reals': flds = and_or_form_creator(_('Fraza'), 'add-phrase-1-{}'.format(n), field=self.make_field(uniq_name), data_prefix='phrase_') elif name.endswith('_lexes'): flds = and_or_form_creator(_('Fraza'), 'add-phrase-2-{}'.format(n), field=self.make_field(uniq_name), data_prefix='phrase_lex') elif name.endswith('_lex'): flds = and_or_form_creator(_('Fraza'), 'add-phrase-3-{}'.format(n), field=self.make_field(uniq_name), data_prefix='phrase_lex') elif name == 'phrase': flds = and_or_form_creator(_('Fraza'), 'add-phrase-4-{}'.format(n), field=self.make_field(uniq_name), data_prefix='phrase_') else: flds = [self.make_field(uniq_name)] components += flds pt = polish_strings.PHRASE_TYPE()[phrase_type] header = pt.capitalize() if phrase_type in polish_strings.NO_PHRASE_NAME else format_lazy(_('Fraza {}'), pt) if lex_model: header += ' ({})'.format(_('zleksykalizowana')) self.helper.layout = cls.make_layout( header.capitalize(), components ) # add a phrase type query def get_queries(self, negated_attrs): pt_q = Q(('{}main_type__name'.format('lexicalized_phrase__' if lex_phrase else ''), phrase_type)) return super().get_queries(negated_attrs) + [pt_q] @staticmethod def get_child_form_prefix(child_form): if model == XPAttributes and child_form.model_class == PhraseType: return 'attributes__xpattributes__reals__in' if model == AdvPAttributes and child_form.model_class == PhraseType: return 'attributes__advpattributes__reals__in' if model == ComparAttributes and child_form.model_class == PhraseType: return 'attributes__lexphrasetypeattributes__lexcomparattributes__lexes__in' if model == FixedAttributes and child_form.model_class == PhraseType: return 'attributes__fixedattributes__phrase__in' print(model, child_form.model_class) raise KeyError(type(child_form)) AttributesForm.base_fields[cls.unique_name('negated', n)] = SwitchField(_('Zaneguj'), css_class='negate-switch') for field, name in all_fields: #print('***', name, field.name, type(field)) if field.name == 'reals': queryset = None if model == XPAttributes: # choice only from phrase types that are realisations of some XP queryset = PhraseTypeModel.objects.filter(main_phrase_types__xpattributes__isnull=False).distinct() if model == AdvPAttributes: # choice only from phrase types that are realisations of some AdvP queryset = PhraseTypeModel.objects.filter(main_phrase_types__advpattributes__isnull=False).distinct() form_field = PhraseTypeFilter(queryset=queryset, help_text=_('Realizacja składniowa frazy.')) elif field.name == 'lexes': form_field = PhraseTypeFilter( queryset=PhraseTypeModel.objects.filter(main_phrase_types__lex_phrases__lexcomparattributes__isnull=False).distinct(), help_text=_('Fraza składowa zleksykalizowanej konstrukcji porównawczej.'), lex=True) elif field.name == 'lex': form_field = PhraseTypeFilter(help_text=_('Fraza zleksykalizowana.')) elif field.name == 'phrase': form_field = PhraseTypeFilter( queryset=PhraseTypeModel.objects.filter(main_phrase_types__fixedattributes__isnull=False).distinct(), help_text=_('Typ składniowy frazy zleksykalizowanej.')) elif type(field) == CharField: # TODO other autocompletes? autocomplete = 'fixed' if field.name == 'text' else None form_field = RegexFilter( label=polish_strings.PHRASE_ATTRIBUTE().get(field.name, field.name), lookup='attributes__{}attributes__{}'.format(phrase_type, field.name), max_length=200, autocomplete=autocomplete, ) else: lex_attr = name.startswith('lex') queryset_q = Q(('{}{}attributes__isnull'.format('lex' if lex_attr else '', phrase_type), False)) queryset = type(field.related_model()).objects.filter(queryset_q).distinct() form_field = ModelMultipleChoiceFilter( label=polish_strings.PHRASE_ATTRIBUTE().get(field.name, field.name), queryset=queryset, key='name', human_values=polish_strings.PHRASE_ATTRIBUTE_VALUE(), checkboxes=(len(queryset) <= 8), lookup='{}attributes__{}{}attributes__{}'.format( 'lexicalized_phrase__' if lex_phrase and not lex_attr else '', 'lexphrasetypeattributes__lex' if lex_attr else '', phrase_type, field.name, ), ) AttributesForm.base_fields[cls.unique_name(name, n)] = form_field return AttributesForm @classmethod def get_form(cls, phrase_type, unique_number=None, *args, **kwargs): unique_number = cls.unique_number() if unique_number is None else unique_number lex = phrase_type.startswith('lex') phrase_type = phrase_type[3:] if lex else phrase_type form_class = None if phrase_type in attrs_helpers: helper = attrs_helpers[phrase_type] attrs_cls, lex_attrs_cls = helper.attrs_cls, helper.lex_attrs_cls if lex: assert(lex_attrs_cls is not None) form_class = cls.make_form_class(unique_number, attrs_cls, lex_attrs_cls, phrase_type) else: form_class = cls.make_form_class(unique_number, attrs_cls, None, phrase_type) if form_class is None: form_class = cls.make_form_class(unique_number, EmptyAttributes, None, phrase_type) return form_class(*args, **kwargs)