mirror of
https://github.com/django/django.git
synced 2025-01-19 14:52:54 +00:00
e542e81b39
The old names were downright confusing. Some seemed to mean the opposite of what the class actually did. The new names follow a consistent nomenclature: (Forward|Reverse)(ManyToOne|OneToOne|ManyToMany)Descriptor. I mentioned combinations that do not exist in the docstring in order to help people who would search for them in the code base.
68 lines
2.8 KiB
Python
68 lines
2.8 KiB
Python
from django.db import models
|
|
from django.db.models.fields.related import (
|
|
RECURSIVE_RELATIONSHIP_CONSTANT, ManyToManyDescriptor,
|
|
ManyToManyField, ManyToManyRel, RelatedField,
|
|
create_many_to_many_intermediary_model,
|
|
)
|
|
from django.utils.functional import curry
|
|
|
|
|
|
class CustomManyToManyField(RelatedField):
|
|
"""
|
|
Ticket #24104 - Need to have a custom ManyToManyField,
|
|
which is not an inheritor of ManyToManyField.
|
|
"""
|
|
many_to_many = True
|
|
|
|
def __init__(self, to, db_constraint=True, swappable=True, **kwargs):
|
|
try:
|
|
to._meta
|
|
except AttributeError:
|
|
to = str(to)
|
|
kwargs['rel'] = ManyToManyRel(
|
|
self, to,
|
|
related_name=kwargs.pop('related_name', None),
|
|
related_query_name=kwargs.pop('related_query_name', None),
|
|
limit_choices_to=kwargs.pop('limit_choices_to', None),
|
|
symmetrical=kwargs.pop('symmetrical', to == RECURSIVE_RELATIONSHIP_CONSTANT),
|
|
through=kwargs.pop('through', None),
|
|
through_fields=kwargs.pop('through_fields', None),
|
|
db_constraint=db_constraint,
|
|
)
|
|
self.swappable = swappable
|
|
self.db_table = kwargs.pop('db_table', None)
|
|
if kwargs['rel'].through is not None:
|
|
assert self.db_table is None, "Cannot specify a db_table if an intermediary model is used."
|
|
super(CustomManyToManyField, self).__init__(**kwargs)
|
|
|
|
def contribute_to_class(self, cls, name, **kwargs):
|
|
if self.remote_field.symmetrical and (
|
|
self.remote_field.model == "self" or self.remote_field.model == cls._meta.object_name):
|
|
self.remote_field.related_name = "%s_rel_+" % name
|
|
super(CustomManyToManyField, self).contribute_to_class(cls, name, **kwargs)
|
|
if not self.remote_field.through and not cls._meta.abstract and not cls._meta.swapped:
|
|
self.remote_field.through = create_many_to_many_intermediary_model(self, cls)
|
|
setattr(cls, self.name, ManyToManyDescriptor(self.remote_field))
|
|
self.m2m_db_table = curry(self._get_m2m_db_table, cls._meta)
|
|
|
|
def get_internal_type(self):
|
|
return 'ManyToManyField'
|
|
|
|
# Copy those methods from ManyToManyField because they don't call super() internally
|
|
contribute_to_related_class = ManyToManyField.__dict__['contribute_to_related_class']
|
|
_get_m2m_attr = ManyToManyField.__dict__['_get_m2m_attr']
|
|
_get_m2m_reverse_attr = ManyToManyField.__dict__['_get_m2m_reverse_attr']
|
|
_get_m2m_db_table = ManyToManyField.__dict__['_get_m2m_db_table']
|
|
|
|
|
|
class InheritedManyToManyField(ManyToManyField):
|
|
pass
|
|
|
|
|
|
class MediumBlobField(models.BinaryField):
|
|
"""
|
|
A MySQL BinaryField that uses a different blob size.
|
|
"""
|
|
def db_type(self, connection):
|
|
return 'MEDIUMBLOB'
|