| 2049 | return getattr(self, cache_attr) |
| 2050 | |
| 2051 | def contribute_to_class(self, cls, name, **kwargs): |
| 2052 | # To support multiple relations to self, it's useful to have a non-None |
| 2053 | # related name on symmetrical relations for internal reasons. The |
| 2054 | # concept doesn't make a lot of sense externally ("you want me to |
| 2055 | # specify *what* on my non-reversible relation?!"), so we set it up |
| 2056 | # automatically. The funky name reduces the chance of an accidental |
| 2057 | # clash. |
| 2058 | if self.remote_field.symmetrical and ( |
| 2059 | self.remote_field.model == RECURSIVE_RELATIONSHIP_CONSTANT |
| 2060 | or self.remote_field.model == cls._meta.object_name |
| 2061 | ): |
| 2062 | self.remote_field.related_name = "%s_rel_+" % name |
| 2063 | elif self.remote_field.hidden: |
| 2064 | # If the backwards relation is disabled, replace the original |
| 2065 | # related_name with one generated from the m2m field name. Django |
| 2066 | # still uses backwards relations internally and we need to avoid |
| 2067 | # clashes between multiple m2m fields with related_name == '+'. |
| 2068 | self.remote_field.related_name = "_%s_%s_%s_+" % ( |
| 2069 | cls._meta.app_label, |
| 2070 | cls.__name__.lower(), |
| 2071 | name, |
| 2072 | ) |
| 2073 | |
| 2074 | super().contribute_to_class(cls, name, **kwargs) |
| 2075 | |
| 2076 | # The intermediate m2m model is not auto created if: |
| 2077 | # 1) There is a manually specified intermediate, or |
| 2078 | # 2) The class owning the m2m field is abstract. |
| 2079 | # 3) The class owning the m2m field has been swapped out. |
| 2080 | if not cls._meta.abstract: |
| 2081 | if self.remote_field.through: |
| 2082 | |
| 2083 | def resolve_through_model(_, model, field): |
| 2084 | field.remote_field.through = model |
| 2085 | |
| 2086 | lazy_related_operation( |
| 2087 | resolve_through_model, cls, self.remote_field.through, field=self |
| 2088 | ) |
| 2089 | elif not cls._meta.swapped: |
| 2090 | self.remote_field.through = create_many_to_many_intermediary_model( |
| 2091 | self, cls |
| 2092 | ) |
| 2093 | |
| 2094 | # Add the descriptor for the m2m relation. |
| 2095 | setattr(cls, self.name, ManyToManyDescriptor(self.remote_field, reverse=False)) |
| 2096 | |
| 2097 | # Set up the accessor for the m2m table name for the relation. |
| 2098 | self.m2m_db_table = partial(self._get_m2m_db_table, cls._meta) |
| 2099 | |
| 2100 | def contribute_to_related_class(self, cls, related): |
| 2101 | # Internal M2Ms (i.e., those with a related name ending with '+') |