forms.py 9.84 KB
from django import forms

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, PhraseType
from semantics.models import FrameOpinion, SemanticRole, RoleAttribute

from .generic_fields import (
    RangeFilter,
    RegexFilter,
    ModelChoiceFilter,
    MultipleChoiceFilter,
    ModelMultipleChoiceFilter,
    OperatorField,
    SwitchField,
)

from .specialised_fields import (
    PhraseoFilter,
    ArgumentFilter,
    PredefinedPreferenceFilter,
    RelationalPreferenceFilter,
    SynsetPreferenceFilter,
)

#from .layouts import Formset

from . import polish_strings

'''
class ArgumentFiltersForm(forms.Form):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.form_method = 'get'
        #self.helper.form_action = 'filters:get_entries'
        self.helper.form_id = 'argument-filters-form'
        #self.helper.form_class = 'form-horizontal'
        #self.helper.label_class = 'col-sm-2'
        #self.helper.field_class = 'col-sm-8'
        
        self.helper.layout = layout.Layout(
            layout.Row(
                layout.Field('argument_role'),
                layout.Field('argument_role_attribute'),
            )
        )
    argument_role = forms.CharField()
    argument_role_attribute = forms.CharField()

ArgumentFormSet = forms.formset_factory(ArgumentFiltersForm)

class ArgumentField(forms.Field, ArgumentFormSet):
    
     def layout(self, x):
        return layout.Fieldset(self.label, Formset(x))
    
     def __init__(self, *args, **kwargs):
        super().__init__(required=False, *args, **kwargs)
        self.label = 'Argumenty semantyczne'
'''

class FiltersForm(forms.Form):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.form_method = 'get'
        self.helper.form_action = 'filters:get_entries'
        self.helper.form_id = 'filters-form'
        self.helper.form_class = 'form-horizontal'
        self.helper.label_class = 'col-sm-2'
        self.helper.field_class = 'col-sm-8'
        
        components = []
        field_groups = []
        all_fields = FiltersForm.base_fields.items()
        for gen, name in (('haseł', 'entry_'), ('schematów', 'schema_'), ('ram', 'frame_')):
            fields = [i for i in all_fields if name in i[0]]
            #field_group = FiltersForm.make_field_group('Filtrowanie według {}'.format(gen), fields, layout.Fieldset)
            field_group = FiltersForm.make_field_group('Filtrowanie według {}'.format(gen), fields, bootstrap.Tab)
            field_groups.append(field_group)
        components.append(bootstrap.TabHolder(*field_groups))
        components.append(layout.Submit('filters-submit', 'Filtruj'))
        self.helper.layout = layout.Layout(*components)
        
    # TODO this is ugly!
    def make_field_group(title, fields, cls):
        args = [title]
        for field_name, field_object in fields:
            #print(field_name, repr(field_object), field_object.layout)
            args.append(field_object.layout(field_name))
        return cls(*args)
    
    def get_queries(self, filter_type=None):
        queries = []
        for key, value in self.cleaned_data.items():
            print(key, value)
            if value and not key.startswith('operator') and not key.startswith('filter'):
                if filter_type is not None and key.split('_')[0] != filter_type:
                    continue
                form_field = self.fields[key]
                operator_key = 'operator_{}'.format(key)
                # TODO conjunction variable is only needed if filter_type is None?
                conjunction = self.cleaned_data.get(operator_key)
                if conjunction is None:
                    conjunction = form_field.query_manager.default_conjunction
                if filter_type is not None:
                    queries += form_field.query_manager.make_object_queries(value)
                else:
                    queries += form_field.query_manager.make_entry_queries(value, conjunction)
        return queries
    
    # ENTRY FILTERS ============================================================
    entry_lemma = RegexFilter(
        label='Lemat',
        entry_lookup='name',
        object_lookup=None,
        max_length=200,
    )
    entry_pos = ModelMultipleChoiceFilter(
        label='Część mowy',
        queryset=POS.objects.exclude(tag='unk'),
        key='tag',
        human_values=polish_strings.POS,
        entry_lookup='pos',
        object_lookup=None,
    )
    entry_phraseology = PhraseoFilter()
    entry_status = ModelMultipleChoiceFilter(
        label ='Status',
        queryset=Status.objects.all().order_by('-priority'),
        key = 'key',
        entry_lookup='status',
        object_lookup=None,
    )
    entry_num_schemata = RangeFilter(
        label='Liczba schematów',
        entry_lookup='schemata_count',
        object_lookup=None,
    )
    entry_num_frames = RangeFilter(
        label='Liczba ram',
        entry_lookup='frames_count',
        object_lookup=None,
    )
    
    # SCHEMA FILTERS ===========================================================
    schema_opinion = ModelMultipleChoiceFilter(
        label='Opinia o schemacie',
        queryset=SchemaOpinion.objects.all(),
        key='key',
        human_values=polish_strings.SCHEMA_OPINION,
        entry_lookup='subentries__schemata__opinion',
        object_lookup='opinion',
        #initial=SchemaOpinion.objects.filter(key__in=('cer', 'vul')),
    )
    operator_schema_opinion = OperatorField()
    schema_type = MultipleChoiceFilter(
        label='Typ',
        choices=((False, 'normalny'), (True, 'frazeologiczny'),),
        entry_lookup='subentries__schemata__phraseologic',
        object_lookup='phraseologic',
    )
    operator_schema_type = OperatorField()
    schema_sie = ModelMultipleChoiceFilter(
        label='Zwrotność',
        queryset=InherentSie.objects.all().order_by('-priority'),
        key='name',
        human_values=polish_strings.TRUE_FALSE_YES_NO,
        entry_lookup='subentries__schemata__inherent_sie',
        object_lookup='inherent_sie',
    )
    operator_schema_sie = OperatorField()
    schema_neg = ModelMultipleChoiceFilter(
        label='Negatywność',
        queryset=Negativity.objects.exclude(name='').order_by('-priority'),
        key='name',
        human_values=polish_strings.NEGATION,
        entry_lookup='subentries__negativity',
        # both Schema and Entry have the same related name for Subentry:
        # can use the same lookup path
        object_lookup=None,
    )
    operator_schema_neg = OperatorField()
    schema_pred = ModelMultipleChoiceFilter(
        label='Predykatywność',
        queryset=Predicativity.objects.all().order_by('-priority'),
        key='name',
        human_values=polish_strings.TRUE_FALSE_YES_NO,
        entry_lookup='subentries__predicativity',
        # both Schema and Entry have the same related name for Subentry:
        # can use the same lookup path
        object_lookup=None,
    )
    operator_schema_pred = OperatorField()
    schema_aspect = ModelMultipleChoiceFilter(
        label='Aspekt',
        queryset=Aspect.objects.exclude(name='').exclude(name='_').order_by('-priority'),
        key='name',
        human_values=polish_strings.ASPECT,
        entry_lookup='subentries__aspect',
        # both Schema and Entry have the same related name for Subentry:
        # can use the same lookup path
        object_lookup=None,
    )
    operator_schema_aspect = OperatorField()
    schema_phrase = RegexFilter(
        label='Fraza',
        max_length=200,
        #initial='.*ręka.* | [xp\(abl\) & xp\(adl\) & [xp\(dur\) | xp\(caus\)]]',
        #initial='xp\(abl\) & xp\(adl\)',
        #initial='np.* !& !np.* | xp.*',
        #entry_lookup='subentries__schemata__position__phrase_types__text_rep',
        entry_lookup=None,
        object_lookup='positions__phrase_types__text_rep',
        inner_class=Schema,
        outer_lookup='subentries__schemata__in',
        additional_operators=True,
    )
    schema_num_positions = RangeFilter(
        label='Liczba pozycyj',
        entry_lookup='subentries__schemata__positions_count',
        object_lookup='positions_count',
    )
    schema_num_phrase_types = RangeFilter(
        label='Liczba typów fraz w pozycji',
        entry_lookup='subentries__schemata__positions__phrases_count',
        object_lookup='positions__phrases_count',
    )
    filter_schema_ = SwitchField('Filtruj schematy')
    
    # FRAME FILTERS ============================================================
    frame_opinion = ModelMultipleChoiceFilter(
        label='Opinia',
        queryset=FrameOpinion.objects.exclude(key='unk').order_by('-priority'),
        key='key',
        human_values=polish_strings.FRAME_OPINION,
        entry_lookup='subentries__schema_hooks__argument_connections__argument__frame__opinion',
        object_lookup='opinion',
    )
    operator_frame_opinion = OperatorField()
    frame_argument = ArgumentFilter()
    frame_predefined = PredefinedPreferenceFilter()
    frame_relational = RelationalPreferenceFilter()
    frame_synset = SynsetPreferenceFilter()
    frame_num_arguments = RangeFilter(
        label='Liczba argumentów',
        entry_lookup='subentries__schema_hooks__argument_connections__argument__frame__arguments_count',
        object_lookup='arguments_count',
    )
    frame_num_preferences = RangeFilter(
        label='Liczba preferencyj selekcyjnych argumentu',
        entry_lookup='subentries__schema_hooks__argument_connections__argument__preferences_count',
        object_lookup='argument__preferences_count',
    )
    filter_frame_ = SwitchField('Filtruj ramy')