filters.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  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 django.db.models import Q
  6. from taggit.models import Tag
  7. from dcim.models import Site
  8. from .constants import CF_FILTER_DISABLED, CF_FILTER_EXACT, CF_TYPE_BOOLEAN, CF_TYPE_SELECT
  9. from .models import CustomField, Graph, ExportTemplate, ObjectChange, TopologyMap, UserAction
  10. class CustomFieldFilter(django_filters.Filter):
  11. """
  12. Filter objects by the presence of a CustomFieldValue. The filter's name is used as the CustomField name.
  13. """
  14. def __init__(self, custom_field, *args, **kwargs):
  15. self.cf_type = custom_field.type
  16. self.filter_logic = custom_field.filter_logic
  17. super(CustomFieldFilter, self).__init__(*args, **kwargs)
  18. def filter(self, queryset, value):
  19. # Skip filter on empty value
  20. if not value.strip():
  21. return queryset
  22. # Selection fields get special treatment (values must be integers)
  23. if self.cf_type == CF_TYPE_SELECT:
  24. try:
  25. # Treat 0 as None
  26. if int(value) == 0:
  27. return queryset.exclude(
  28. custom_field_values__field__name=self.name,
  29. )
  30. # Match on exact CustomFieldChoice PK
  31. else:
  32. return queryset.filter(
  33. custom_field_values__field__name=self.name,
  34. custom_field_values__serialized_value=value,
  35. )
  36. except ValueError:
  37. return queryset.none()
  38. # Apply the assigned filter logic (exact or loose)
  39. if self.cf_type == CF_TYPE_BOOLEAN or self.filter_logic == CF_FILTER_EXACT:
  40. queryset = queryset.filter(
  41. custom_field_values__field__name=self.name,
  42. custom_field_values__serialized_value=value
  43. )
  44. else:
  45. queryset = queryset.filter(
  46. custom_field_values__field__name=self.name,
  47. custom_field_values__serialized_value__icontains=value
  48. )
  49. return queryset
  50. class CustomFieldFilterSet(django_filters.FilterSet):
  51. """
  52. Dynamically add a Filter for each CustomField applicable to the parent model.
  53. """
  54. def __init__(self, *args, **kwargs):
  55. super(CustomFieldFilterSet, self).__init__(*args, **kwargs)
  56. obj_type = ContentType.objects.get_for_model(self._meta.model)
  57. custom_fields = CustomField.objects.filter(obj_type=obj_type).exclude(filter_logic=CF_FILTER_DISABLED)
  58. for cf in custom_fields:
  59. self.filters['cf_{}'.format(cf.name)] = CustomFieldFilter(name=cf.name, custom_field=cf)
  60. class GraphFilter(django_filters.FilterSet):
  61. class Meta:
  62. model = Graph
  63. fields = ['type', 'name']
  64. class ExportTemplateFilter(django_filters.FilterSet):
  65. class Meta:
  66. model = ExportTemplate
  67. fields = ['content_type', 'name']
  68. class TagFilter(django_filters.FilterSet):
  69. q = django_filters.CharFilter(
  70. method='search',
  71. label='Search',
  72. )
  73. class Meta:
  74. model = Tag
  75. fields = ['name', 'slug']
  76. def search(self, queryset, name, value):
  77. if not value.strip():
  78. return queryset
  79. return queryset.filter(
  80. Q(name__icontains=value) |
  81. Q(slug__icontains=value)
  82. )
  83. class TopologyMapFilter(django_filters.FilterSet):
  84. site_id = django_filters.ModelMultipleChoiceFilter(
  85. name='site',
  86. queryset=Site.objects.all(),
  87. label='Site',
  88. )
  89. site = django_filters.ModelMultipleChoiceFilter(
  90. name='site__slug',
  91. queryset=Site.objects.all(),
  92. to_field_name='slug',
  93. label='Site (slug)',
  94. )
  95. class Meta:
  96. model = TopologyMap
  97. fields = ['name', 'slug']
  98. class ObjectChangeFilter(django_filters.FilterSet):
  99. q = django_filters.CharFilter(
  100. method='search',
  101. label='Search',
  102. )
  103. time = django_filters.DateTimeFromToRangeFilter()
  104. class Meta:
  105. model = ObjectChange
  106. fields = ['user', 'user_name', 'request_id', 'action', 'changed_object_type', 'object_repr']
  107. def search(self, queryset, name, value):
  108. if not value.strip():
  109. return queryset
  110. return queryset.filter(
  111. Q(user_name__icontains=value) |
  112. Q(object_repr__icontains=value)
  113. )
  114. class UserActionFilter(django_filters.FilterSet):
  115. username = django_filters.ModelMultipleChoiceFilter(
  116. name='user__username',
  117. queryset=User.objects.all(),
  118. to_field_name='username',
  119. )
  120. class Meta:
  121. model = UserAction
  122. fields = ['user']