filters.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. from __future__ import unicode_literals
  2. import django_filters
  3. from django.contrib.auth.models import User
  4. from django.contrib.contenttypes.models import ContentType
  5. from dcim.models import Site
  6. from .constants import CF_FILTER_DISABLED, CF_FILTER_EXACT, CF_TYPE_BOOLEAN, CF_TYPE_SELECT
  7. from .models import CustomField, Graph, ExportTemplate, TopologyMap, UserAction
  8. class CustomFieldFilter(django_filters.Filter):
  9. """
  10. Filter objects by the presence of a CustomFieldValue. The filter's name is used as the CustomField name.
  11. """
  12. def __init__(self, custom_field, *args, **kwargs):
  13. self.cf_type = custom_field.type
  14. self.filter_logic = custom_field.filter_logic
  15. super(CustomFieldFilter, self).__init__(*args, **kwargs)
  16. def filter(self, queryset, value):
  17. # Skip filter on empty value
  18. if not value.strip():
  19. return queryset
  20. # Selection fields get special treatment (values must be integers)
  21. if self.cf_type == CF_TYPE_SELECT:
  22. try:
  23. # Treat 0 as None
  24. if int(value) == 0:
  25. return queryset.exclude(
  26. custom_field_values__field__name=self.name,
  27. )
  28. # Match on exact CustomFieldChoice PK
  29. else:
  30. return queryset.filter(
  31. custom_field_values__field__name=self.name,
  32. custom_field_values__serialized_value=value,
  33. )
  34. except ValueError:
  35. return queryset.none()
  36. # Apply the assigned filter logic (exact or loose)
  37. queryset = queryset.filter(custom_field_values__field__name=self.name)
  38. if self.cf_type == CF_TYPE_BOOLEAN or self.filter_logic == CF_FILTER_EXACT:
  39. return queryset.filter(custom_field_values__serialized_value=value)
  40. else:
  41. return queryset.filter(custom_field_values__serialized_value__icontains=value)
  42. class CustomFieldFilterSet(django_filters.FilterSet):
  43. """
  44. Dynamically add a Filter for each CustomField applicable to the parent model.
  45. """
  46. def __init__(self, *args, **kwargs):
  47. super(CustomFieldFilterSet, self).__init__(*args, **kwargs)
  48. obj_type = ContentType.objects.get_for_model(self._meta.model)
  49. custom_fields = CustomField.objects.filter(obj_type=obj_type).exclude(filter_logic=CF_FILTER_DISABLED)
  50. for cf in custom_fields:
  51. self.filters['cf_{}'.format(cf.name)] = CustomFieldFilter(name=cf.name, custom_field=cf)
  52. class GraphFilter(django_filters.FilterSet):
  53. class Meta:
  54. model = Graph
  55. fields = ['type', 'name']
  56. class ExportTemplateFilter(django_filters.FilterSet):
  57. class Meta:
  58. model = ExportTemplate
  59. fields = ['content_type', 'name']
  60. class TopologyMapFilter(django_filters.FilterSet):
  61. site_id = django_filters.ModelMultipleChoiceFilter(
  62. name='site',
  63. queryset=Site.objects.all(),
  64. label='Site',
  65. )
  66. site = django_filters.ModelMultipleChoiceFilter(
  67. name='site__slug',
  68. queryset=Site.objects.all(),
  69. to_field_name='slug',
  70. label='Site (slug)',
  71. )
  72. class Meta:
  73. model = TopologyMap
  74. fields = ['name', 'slug']
  75. class UserActionFilter(django_filters.FilterSet):
  76. username = django_filters.ModelMultipleChoiceFilter(
  77. name='user__username',
  78. queryset=User.objects.all(),
  79. to_field_name='username',
  80. )
  81. class Meta:
  82. model = UserAction
  83. fields = ['user']