filters.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  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. if self.cf_type == CF_TYPE_BOOLEAN or self.filter_logic == CF_FILTER_EXACT:
  38. queryset = queryset.filter(
  39. custom_field_values__field__name=self.name,
  40. custom_field_values__serialized_value=value
  41. )
  42. else:
  43. queryset = queryset.filter(
  44. custom_field_values__field__name=self.name,
  45. custom_field_values__serialized_value__icontains=value
  46. )
  47. return queryset
  48. class CustomFieldFilterSet(django_filters.FilterSet):
  49. """
  50. Dynamically add a Filter for each CustomField applicable to the parent model.
  51. """
  52. def __init__(self, *args, **kwargs):
  53. super(CustomFieldFilterSet, self).__init__(*args, **kwargs)
  54. obj_type = ContentType.objects.get_for_model(self._meta.model)
  55. custom_fields = CustomField.objects.filter(obj_type=obj_type).exclude(filter_logic=CF_FILTER_DISABLED)
  56. for cf in custom_fields:
  57. self.filters['cf_{}'.format(cf.name)] = CustomFieldFilter(name=cf.name, custom_field=cf)
  58. class GraphFilter(django_filters.FilterSet):
  59. class Meta:
  60. model = Graph
  61. fields = ['type', 'name']
  62. class ExportTemplateFilter(django_filters.FilterSet):
  63. class Meta:
  64. model = ExportTemplate
  65. fields = ['content_type', 'name']
  66. class TopologyMapFilter(django_filters.FilterSet):
  67. site_id = django_filters.ModelMultipleChoiceFilter(
  68. name='site',
  69. queryset=Site.objects.all(),
  70. label='Site',
  71. )
  72. site = django_filters.ModelMultipleChoiceFilter(
  73. name='site__slug',
  74. queryset=Site.objects.all(),
  75. to_field_name='slug',
  76. label='Site (slug)',
  77. )
  78. class Meta:
  79. model = TopologyMap
  80. fields = ['name', 'slug']
  81. class UserActionFilter(django_filters.FilterSet):
  82. username = django_filters.ModelMultipleChoiceFilter(
  83. name='user__username',
  84. queryset=User.objects.all(),
  85. to_field_name='username',
  86. )
  87. class Meta:
  88. model = UserAction
  89. fields = ['user']