Projet

Général

Profil

0001-misc-extend-filter_by-to-work-with-fields-with-non-u.patch

Frédéric Péters, 19 octobre 2021 16:32

Télécharger (7,77 ko)

Voir les différences:

Subject: [PATCH] misc: extend |filter_by to work with fields with non-unique
 varname (#56614)

 tests/test_formdata.py | 55 ++++++++++++++++++++++++++++++++++++++----
 wcs/variables.py       | 46 +++++++++++++++++++++++------------
 2 files changed, 81 insertions(+), 20 deletions(-)
tests/test_formdata.py
1277 1277
        queryset = lazy_formdata.objects.filter_by('datefield').apply_exclude_value(
1278 1278
            datetime.date(2018, 7, 31).timetuple()
1279 1279
        )
1280
        assert queryset.count == 1
1280
        assert queryset.count == 6  # 1 + 5 null
1281 1281
        queryset = lazy_formdata.objects.filter_by('datefield').apply_exclude_value(
1282 1282
            datetime.date(2018, 7, 31)
1283 1283
        )
1284
        assert queryset.count == 1
1284
        assert queryset.count == 6
1285 1285
        queryset = lazy_formdata.objects.filter_by('datefield').apply_exclude_value(
1286 1286
            datetime.datetime(2018, 7, 31)
1287 1287
        )
1288
        assert queryset.count == 1
1288
        assert queryset.count == 6
1289 1289
        queryset = lazy_formdata.objects.filter_by('datefield').apply_exclude_value('2018-07-31')
1290
        assert queryset.count == 1
1290
        assert queryset.count == 6
1291 1291
        queryset = lazy_formdata.objects.filter_by('datefield').apply_exclude_value('still not a date')
1292 1292
        assert queryset.count == 0
1293 1293
        assert pub.loggederror_class.count() == 3
......
1394 1394
        tmpl = Template('{{form_objects|filter_by:"foo_foo"|exclude_value:form_var_foo_foo|count}}')
1395 1395
        assert tmpl.render(context) == '4'
1396 1396
        tmpl = Template('{{form_objects|filter_by:"datefield"|exclude_value:form_var_datefield|count}}')
1397
        assert tmpl.render(context) == '1'
1397
        assert tmpl.render(context) == '6'
1398 1398
        tmpl = Template('{{form_objects|filter_by:"boolfield"|exclude_value:form_var_boolfield|count}}')
1399 1399
        assert tmpl.render(context) == '6'
1400 1400
        tmpl = Template('{{form_objects|filter_by:"term1"|exclude_value:form_var_term1|count}}')
......
1547 1547
    assert 'not a date' not in LazyFormData(formdata).objects.getlist('datefield')
1548 1548

  
1549 1549

  
1550
def test_lazy_formdata_queryset_filter_non_unique_varname(pub, variable_test_data):
1551
    lazy_formdata = variable_test_data
1552
    formdef = lazy_formdata._formdef
1553
    # modify fields to have foo_foo as varname for both fields[0] and fields[7]
1554
    assert formdef.fields[7].label == 'string2'
1555
    formdef.fields[7].varname = 'foo_foo'
1556
    formdef.store()
1557

  
1558
    data_class = lazy_formdata._formdef.data_class()
1559
    for i in range(6):
1560
        formdata = data_class()
1561
        formdata.data = {'0': 'bar', '6': 'baz'}
1562
        if i == 5:
1563
            formdata.data['3'] = datetime.date(2018, 8, 31).timetuple()
1564
        formdata.just_created()
1565
        formdata.store()
1566
    formdatas = []
1567
    for _ in range(4):
1568
        formdata = data_class()
1569
        formdata.data = {
1570
            '0': 'foo',
1571
        }
1572
        formdata.just_created()
1573
        formdata.jump_status('finished')
1574
        formdata.store()
1575
        formdatas.append(formdata)
1576

  
1577
    context = pub.substitutions.get_context_variables(mode='lazy')
1578
    tmpl = Template('{{form_objects|filter_by:"foo_foo"|filter_value:"bar"|count}}')
1579
    assert tmpl.render(context) == '7'
1580
    tmpl = Template('{{form_objects|filter_by:"foo_foo"|filter_value:"other"|count}}')
1581
    assert tmpl.render(context) == '1'
1582
    tmpl = Template('{{form_objects|filter_by:"foo_foo"|filter_value:"baz"|count}}')
1583
    assert tmpl.render(context) == '6'
1584
    tmpl = Template('{{form_objects|filter_by:"foo_foo"|exclude_value:"bar"|count}}')
1585
    assert tmpl.render(context) == '4'  # 11 - 7
1586

  
1587
    for formdata in formdatas[:-1]:
1588
        formdata.data['6'] = 'bar'
1589
        formdata.store()
1590

  
1591
    tmpl = Template('{{form_objects|filter_by:"foo_foo"|exclude_value:"bar"|count}}')
1592
    assert tmpl.render(context) == '1'
1593

  
1594

  
1550 1595
def test_lazy_formdata_queryset_get_from_first(pub, variable_test_data):
1551 1596
    context = pub.substitutions.get_context_variables(mode='lazy')
1552 1597
    del context['form']  # remove actual form from context
wcs/variables.py
26 26
from .formdef import FormDef
27 27
from .qommon import _, force_str, misc
28 28
from .qommon.evalutils import make_datetime
29
from .qommon.storage import Equal, Intersects, Not, NotEqual, Null, Or
29
from .qommon.storage import And, Equal, Intersects, Not, NotEqual, Null, Or
30 30
from .qommon.substitution import CompatibilityNamesDict
31 31
from .qommon.templatetags.qommon import parse_datetime
32 32

  
......
175 175
    def filter_by_number(self, value):
176 176
        return self._clone(self._criterias + [Equal('id_display', str(value))])
177 177

  
178
    def get_field(self, key):
178
    def get_fields(self, key):
179 179
        for field in self._formdef.get_all_fields():
180 180
            if getattr(field, 'varname', None) == key:
181
                return field
181
                yield field
182

  
183
    def get_field(self, key):
184
        for field in self.get_fields(key):
185
            return field
182 186

  
183 187
    def apply_filter_value(self, value, exclude=False):
184 188
        assert self.pending_attr
185 189

  
186
        field = self.get_field(self.pending_attr)
187
        if field is None:
190
        fields = list(self.get_fields(self.pending_attr))
191
        if not fields:
188 192
            get_publisher().record_error(
189 193
                _('Invalid filter "%s"') % self.pending_attr, formdata=self._formdata
190 194
            )
191 195
            return self.none()
192 196

  
193
        if field.convert_value_from_anything:
197
        if fields[0].convert_value_from_anything:
198
            # consider all fields with same varname are of the same type
199
            # (it should definitely be)
194 200
            try:
195
                value = field.convert_value_from_anything(value)
201
                value = fields[0].convert_value_from_anything(value)
196 202
            except (ValueError, AttributeError):
197 203
                get_publisher().record_error(
198 204
                    _('Invalid value "%s" for filter "%s"') % (value, self.pending_attr),
......
202 208

  
203 209
        from wcs import sql
204 210

  
205
        field_id = sql.get_field_id(field)
206
        if isinstance(value, list):
207
            criterias = Intersects(field_id, value, field=field)
208
        else:
209
            criterias = Equal(field_id, value, field=field)
211
        criterias = []
212
        for field in fields:
213
            field_id = sql.get_field_id(field)
214
            if isinstance(value, list):
215
                criteria = Intersects(field_id, value, field=field)
216
                if exclude:
217
                    criteria = Not(criteria)
218
            elif exclude:
219
                criteria = Or([NotEqual(field_id, value, field=field), Null(field_id)])
220
            else:
221
                criteria = Equal(field_id, value, field=field)
222
            criterias.append(criteria)
210 223

  
211
        if exclude:
212
            criterias = Not(criterias)
224
        if len(criterias) > 1:
225
            if exclude:
226
                criterias = [And(criterias)]
227
            else:
228
                criterias = [Or(criterias)]
213 229

  
214
        return self._clone(self._criterias + [criterias])
230
        return self._clone(self._criterias + criterias)
215 231

  
216 232
    def apply_exclude_value(self, value):
217 233
        return self.apply_filter_value(value, exclude=True)
218
-