dplex 0.3.2__tar.gz → 0.3.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dplex
3
- Version: 0.3.2
3
+ Version: 0.3.3
4
4
  Summary:
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -419,6 +419,9 @@ class FilterApplier:
419
419
  self,
420
420
  query_builder: SupportsFiltering,
421
421
  filter_data: WordsFilter,
422
+ *,
423
+ model: type | None = None,
424
+ field_name: str | None = None,
422
425
  ) -> SupportsFiltering:
423
426
  """
424
427
  Применить фильтр слов к нескольким колонкам
@@ -427,37 +430,41 @@ class FilterApplier:
427
430
  Для каждого слова создается условие OR (слово должно быть найдено хотя бы в одной колонке).
428
431
  Все слова объединяются через AND (все слова должны быть найдены).
429
432
 
430
- Если filter_data.text или filter_data.columns равны None, фильтр не применяется.
433
+ Если filter_data.columns равен None, используются колонка текущего поля (model, field_name).
434
+ При отсутствии поля в модели выбрасывается ValueError.
435
+
436
+ Если filter_data.text пустой, фильтр не применяется.
431
437
 
432
438
  Args:
433
439
  query_builder: Query builder для применения фильтров
434
- filter_data: Экземпляр WordsFilter с указанными колонками
440
+ filter_data: Экземпляр WordsFilter
441
+ model: Модель для разрешения колонки по имени поля (при columns=None)
442
+ field_name: Имя поля для поиска (при columns=None)
435
443
 
436
444
  Returns:
437
445
  Query builder с примененным фильтром слов (или без изменений, если фильтр не активен)
438
446
 
439
- Examples:
440
- >>> from sqlalchemy import and_, or_
441
- >>> words_filter = WordsFilter("john developer", columns=[User.name, User.email])
442
- >>> query = applier.apply_words_filter(query_builder, words_filter)
443
- >>>
444
- >>> # Фильтр не будет применен, если text или columns равны None
445
- >>> inactive_filter = WordsFilter(None, None)
446
- >>> query = applier.apply_words_filter(query_builder, inactive_filter) # вернет query без изменений
447
+ Raises:
448
+ ValueError: Если columns=None, field_name не задан или поле отсутствует в модели
447
449
  """
448
450
  from sqlalchemy import and_, or_
449
451
 
450
- search_columns = filter_data.columns
451
-
452
- # Если columns равны None или пустые, фильтр не применяется
453
- if search_columns is None or not search_columns:
454
- return query_builder
455
-
456
452
  words = filter_data.words
457
- # Если words пустые (text был None или пустой), фильтр не применяется
453
+ # Если text пустой фильтр не применяется (не проверяем columns)
458
454
  if not words:
459
455
  return query_builder
460
456
 
457
+ search_columns = filter_data.columns
458
+ # Если columns заданы — используем их; иначе — колонку текущего поля
459
+ if search_columns is None or not search_columns:
460
+ if model is None or field_name is None:
461
+ return query_builder
462
+ if not hasattr(model, field_name):
463
+ raise ValueError(
464
+ f"WordsFilter: модель {model.__name__} не имеет поля '{field_name}'"
465
+ )
466
+ search_columns = [getattr(model, field_name)]
467
+
461
468
  # Для каждого слова создаем условие: слово должно быть найдено хотя бы в одной колонке (OR)
462
469
  word_conditions = []
463
470
  for word in words:
@@ -516,8 +523,9 @@ class FilterApplier:
516
523
 
517
524
  # Обрабатываем WordsFilter отдельно (может быть кастомным фильтром)
518
525
  if isinstance(field_value, WordsFilter):
519
- # WordsFilter теперь всегда имеет колонки (обязательный параметр)
520
- query_builder = self.apply_words_filter(query_builder, field_value)
526
+ query_builder = self.apply_words_filter(
527
+ query_builder, field_value, model=model, field_name=field_name
528
+ )
521
529
  continue
522
530
 
523
531
  # Пропускаем поля, отсутствующие в модели
@@ -873,30 +873,30 @@ class WordsFilter:
873
873
  Фильтр для поиска по нескольким словам с автоматической разбивкой строки
874
874
 
875
875
  Автоматически разбивает строку на слова и предоставляет их для поиска.
876
- Предназначен для кастомных фильтров, где нужно искать каждое слово
877
- в разных колонках модели.
876
+ Поддерживает два режима:
877
+ - columns задан: поиск в указанных колонках (для кастомных полей вроде query)
878
+ - columns=None: поиск в колонке текущего поля схемы (имя поля = имя колонки модели).
879
+ Если поле отсутствует в модели, при применении фильтра выбрасывается ValueError.
878
880
 
879
881
  Args:
880
882
  text: Строка для поиска, которая будет автоматически разбита на слова.
881
- Если None, фильтр не будет применяться.
883
+ Если None или пустая, фильтр не применяется.
882
884
  columns: Список колонок модели для поиска.
883
- Если None, фильтр не будет применяться.
885
+ Если None, используется колонка текущего поля (где WordsFilter в схеме).
884
886
 
885
887
  Examples:
886
- >>> # Использование с указанием колонок
887
- >>> words_filter = WordsFilter("john developer", columns=[User.name, User.email, User.bio])
888
- >>> # words_filter.words = ["john", "developer"]
888
+ >>> # Поиск по текущему полю (name в схеме -> User.name в модели)
889
+ >>> class UserFilters(DPFilters):
890
+ ... name: WordsFilter | None = None
891
+ >>> filters = UserFilters(name=WordsFilter("john")) # поиск в User.name
889
892
  >>>
890
- >>> # В схеме фильтрации
893
+ >>> # Поиск в нескольких колонках (кастомное поле query)
891
894
  >>> class UserFilters(DPFilters):
892
895
  ... query: WordsFilter | None = None
896
+ >>> filters = UserFilters(query=WordsFilter("john dev", columns=[User.name, User.email, User.bio]))
893
897
  >>>
894
- >>> filters = UserFilters(query=WordsFilter("python developer", columns=[User.name, User.email]))
895
- >>>
896
- >>> # Упрощенное использование: если text или columns равны None, фильтр не применяется
897
- >>> filters = UserFilters(query=WordsFilter(None, None)) # фильтр не будет применен
898
- >>> filters = UserFilters(query=WordsFilter("text", None)) # фильтр не будет применен
899
- >>> filters = UserFilters(query=WordsFilter(None, [User.name])) # фильтр не будет применен
898
+ >>> # Не применяется при пустом text
899
+ >>> filters = UserFilters(name=WordsFilter(None)) # фильтр не будет применен
900
900
  """
901
901
 
902
902
  def __init__(
@@ -907,9 +907,10 @@ class WordsFilter:
907
907
 
908
908
  Args:
909
909
  text: Строка для поиска, которая будет автоматически разбита на слова.
910
- Если None, фильтр не будет применяться.
910
+ Если None, фильтр не применяется.
911
911
  columns: Список колонок модели для поиска.
912
- Если None, фильтр не будет применяться.
912
+ Если None, используется колонка текущего поля (при применении).
913
+ Поле должно существовать в модели, иначе ValueError.
913
914
 
914
915
  Returns:
915
916
  None
@@ -953,8 +954,10 @@ class WordsFilter:
953
954
 
954
955
  def __str__(self) -> str:
955
956
  """Человекочитаемое представление"""
956
- if self.columns is None or not self.text:
957
+ if not self.text:
957
958
  return "WordsFilter(inactive)"
958
959
  if self.words:
959
- return f"WordsFilter({len(self.words)} words: {', '.join(self.words)} in {len(self.columns)} columns)"
960
+ if self.columns:
961
+ return f"WordsFilter({len(self.words)} words: {', '.join(self.words)} in {len(self.columns)} columns)"
962
+ return f"WordsFilter({len(self.words)} words: {', '.join(self.words)} in current field)"
960
963
  return "WordsFilter(empty)"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "dplex"
3
- version = "0.3.2"
3
+ version = "0.3.3"
4
4
  description = ""
5
5
  authors = [
6
6
  {name = "Igor Chesnokov",email = "front-gold@mail.ru"}
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes