related.py 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. from collections import namedtuple
  2. from django.utils.encoding import smart_text
  3. from django.db.models.fields import BLANK_CHOICE_DASH
  4. # PathInfo is used when converting lookups (fk__somecol). The contents
  5. # describe the relation in Model terms (model Options and Fields for both
  6. # sides of the relation. The join_field is the field backing the relation.
  7. PathInfo = namedtuple('PathInfo',
  8. 'from_opts to_opts target_fields join_field '
  9. 'm2m direct')
  10. class RelatedObject(object):
  11. def __init__(self, parent_model, model, field):
  12. self.parent_model = parent_model
  13. self.model = model
  14. self.opts = model._meta
  15. self.field = field
  16. self.name = '%s:%s' % (self.opts.app_label, self.opts.model_name)
  17. self.var_name = self.opts.model_name
  18. def get_choices(self, include_blank=True, blank_choice=BLANK_CHOICE_DASH,
  19. limit_to_currently_related=False):
  20. """Returns choices with a default blank choices included, for use
  21. as SelectField choices for this field.
  22. Analogue of django.db.models.fields.Field.get_choices, provided
  23. initially for utilization by RelatedFieldListFilter.
  24. """
  25. first_choice = blank_choice if include_blank else []
  26. queryset = self.model._default_manager.all()
  27. if limit_to_currently_related:
  28. queryset = queryset.complex_filter(
  29. {'%s__isnull' % self.parent_model._meta.model_name: False})
  30. lst = [(x._get_pk_val(), smart_text(x)) for x in queryset]
  31. return first_choice + lst
  32. def get_db_prep_lookup(self, lookup_type, value, connection, prepared=False):
  33. # Defer to the actual field definition for db prep
  34. return self.field.get_db_prep_lookup(lookup_type, value,
  35. connection=connection, prepared=prepared)
  36. def editable_fields(self):
  37. "Get the fields in this class that should be edited inline."
  38. return [f for f in self.opts.fields + self.opts.many_to_many if f.editable and f != self.field]
  39. def __repr__(self):
  40. return "<RelatedObject: %s related to %s>" % (self.name, self.field.name)
  41. def get_accessor_name(self):
  42. # This method encapsulates the logic that decides what name to give an
  43. # accessor descriptor that retrieves related many-to-one or
  44. # many-to-many objects. It uses the lower-cased object_name + "_set",
  45. # but this can be overridden with the "related_name" option.
  46. if self.field.rel.multiple:
  47. # If this is a symmetrical m2m relation on self, there is no reverse accessor.
  48. if getattr(self.field.rel, 'symmetrical', False) and self.model == self.parent_model:
  49. return None
  50. return self.field.rel.related_name or (self.opts.model_name + '_set')
  51. else:
  52. return self.field.rel.related_name or (self.opts.model_name)
  53. def get_cache_name(self):
  54. return "_%s_cache" % self.get_accessor_name()
  55. def get_path_info(self):
  56. return self.field.get_reverse_path_info()