query.py 1.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
  1. from django.db.models import Count, OuterRef, Subquery
  2. from django.db.models.functions import Coalesce
  3. __all__ = (
  4. 'count_related',
  5. 'dict_to_filter_params',
  6. )
  7. def count_related(model, field):
  8. """
  9. Return a Subquery suitable for annotating a child object count.
  10. """
  11. subquery = Subquery(
  12. model.objects.filter(
  13. **{field: OuterRef('pk')}
  14. ).order_by().values(
  15. field
  16. ).annotate(
  17. c=Count('*')
  18. ).values('c')
  19. )
  20. return Coalesce(subquery, 0)
  21. def dict_to_filter_params(d, prefix=''):
  22. """
  23. Translate a dictionary of attributes to a nested set of parameters suitable for QuerySet filtering. For example:
  24. {
  25. "name": "Foo",
  26. "rack": {
  27. "facility_id": "R101"
  28. }
  29. }
  30. Becomes:
  31. {
  32. "name": "Foo",
  33. "rack__facility_id": "R101"
  34. }
  35. And can be employed as filter parameters:
  36. Device.objects.filter(**dict_to_filter(attrs_dict))
  37. """
  38. params = {}
  39. for key, val in d.items():
  40. k = prefix + key
  41. if isinstance(val, dict):
  42. params.update(dict_to_filter_params(val, k + '__'))
  43. else:
  44. params[k] = val
  45. return params