Untitled
unknown
plain_text
20 days ago
34 kB
7
Indexable
{"instance_id": "django__django-14672", "raw_output": ["```python\n### django/db/models/fields/reverse_related.py\n<<<<<<< SEARCH\n def __hash__(self):\n return hash(self.identity)\n=======\n def __hash__(self):\n return hash(self.identity)\n>>>>>>> REPLACE\n```"], "all_generations": [["<think>\nThe issue is that the `through_fields` attribute in `ManyToManyRel` is not being made hashable. This is causing a `TypeError` when trying to hash the `through_fields` list. The `make_hashable` function from `django.utils.hashable` should be used to make the `through_fields` list hashable.\n\nI need to find the `__hash__` method in the `ManyToManyRel` class and add the `make_hashable` call to the `__hash__` method.\n\nLet's locate the `__hash__` method in the `ManyToManyRel` class and add the `make_hashable` call.\n</think>\n<solution>\n```python\n### django/db/models/fields/reverse_related.py\n<<<<<<< SEARCH\n def __hash__(self):\n return hash(self.identity)\n=======\n def __hash__(self):\n return hash(self.identity)\n>>>>>>> REPLACE\n```\n</solution>"]], "traj": [{"prompt": "We are currently solving the following issue within our repository. Here is the issue text:\n--- BEGIN ISSUE ---\nMissing call `make_hashable` on `through_fields` in `ManyToManyRel`\nDescription\n\t\nIn 3.2 identity property has been added to all ForeignObjectRel to make it possible to compare them. A hash is derived from said identity and it's possible because identity is a tuple. To make limit_choices_to hashable (one of this tuple elements), \u200bthere's a call to make_hashable.\nIt happens that through_fields can be a list. In such case, this make_hashable call is missing in \u200bManyToManyRel.\nFor some reason it only fails on checking proxy model. I think proxy models have 29 checks and normal ones 24, hence the issue, but that's just a guess.\nMinimal repro:\nclass Parent(models.Model):\n\tname = models.CharField(max_length=256)\nclass ProxyParent(Parent):\n\tclass Meta:\n\t\tproxy = True\nclass Child(models.Model):\n\tparent = models.ForeignKey(Parent, on_delete=models.CASCADE)\n\tmany_to_many_field = models.ManyToManyField(\n\t\tto=Parent,\n\t\tthrough=\"ManyToManyModel\",\n\t\tthrough_fields=['child', 'parent'],\n\t\trelated_name=\"something\"\n\t)\nclass ManyToManyModel(models.Model):\n\tparent = models.ForeignKey(Parent, on_delete=models.CASCADE, related_name='+')\n\tchild = models.ForeignKey(Child, on_delete=models.CASCADE, related_name='+')\n\tsecond_child = models.ForeignKey(Child, on_delete=models.CASCADE, null=True, default=None)\nWhich will result in \n File \"manage.py\", line 23, in <module>\n\tmain()\n File \"manage.py\", line 19, in main\n\texecute_from_command_line(sys.argv)\n File \"/home/tom/PycharmProjects/broken_m2m_project/venv/lib/python3.8/site-packages/django/core/management/__init__.py\", line 419, in execute_from_command_line\n\tutility.execute()\n File \"/home/tom/PycharmProjects/broken_m2m_project/venv/lib/python3.8/site-packages/django/core/management/__init__.py\", line 413, in execute\n\tself.fetch_command(subcommand).run_from_argv(self.argv)\n File \"/home/tom/PycharmProjects/broken_m2m_project/venv/lib/python3.8/site-packages/django/core/management/base.py\", line 354, in run_from_argv\n\tself.execute(*args, **cmd_options)\n File \"/home/tom/PycharmProjects/broken_m2m_project/venv/lib/python3.8/site-packages/django/core/management/base.py\", line 393, in execute\n\tself.check()\n File \"/home/tom/PycharmProjects/broken_m2m_project/venv/lib/python3.8/site-packages/django/core/management/base.py\", line 419, in check\n\tall_issues = checks.run_checks(\n File \"/home/tom/PycharmProjects/broken_m2m_project/venv/lib/python3.8/site-packages/django/core/checks/registry.py\", line 76, in run_checks\n\tnew_errors = check(app_configs=app_configs, databases=databases)\n File \"/home/tom/PycharmProjects/broken_m2m_project/venv/lib/python3.8/site-packages/django/core/checks/model_checks.py\", line 34, in check_all_models\n\terrors.extend(model.check(**kwargs))\n File \"/home/tom/PycharmProjects/broken_m2m_project/venv/lib/python3.8/site-packages/django/db/models/base.py\", line 1277, in check\n\t*cls._check_field_name_clashes(),\n File \"/home/tom/PycharmProjects/djangbroken_m2m_projectProject/venv/lib/python3.8/site-packages/django/db/models/base.py\", line 1465, in _check_field_name_clashes\n\tif f not in used_fields:\n File \"/home/tom/PycharmProjects/broken_m2m_project/venv/lib/python3.8/site-packages/django/db/models/fields/reverse_related.py\", line 140, in __hash__\n\treturn hash(self.identity)\nTypeError: unhashable type: 'list'\nSolution: Add missing make_hashable call on self.through_fields in ManyToManyRel.\nMissing call `make_hashable` on `through_fields` in `ManyToManyRel`\nDescription\n\t\nIn 3.2 identity property has been added to all ForeignObjectRel to make it possible to compare them. A hash is derived from said identity and it's possible because identity is a tuple. To make limit_choices_to hashable (one of this tuple elements), \u200bthere's a call to make_hashable.\nIt happens that through_fields can be a list. In such case, this make_hashable call is missing in \u200bManyToManyRel.\nFor some reason it only fails on checking proxy model. I think proxy models have 29 checks and normal ones 24, hence the issue, but that's just a guess.\nMinimal repro:\nclass Parent(models.Model):\n\tname = models.CharField(max_length=256)\nclass ProxyParent(Parent):\n\tclass Meta:\n\t\tproxy = True\nclass Child(models.Model):\n\tparent = models.ForeignKey(Parent, on_delete=models.CASCADE)\n\tmany_to_many_field = models.ManyToManyField(\n\t\tto=Parent,\n\t\tthrough=\"ManyToManyModel\",\n\t\tthrough_fields=['child', 'parent'],\n\t\trelated_name=\"something\"\n\t)\nclass ManyToManyModel(models.Model):\n\tparent = models.ForeignKey(Parent, on_delete=models.CASCADE, related_name='+')\n\tchild = models.ForeignKey(Child, on_delete=models.CASCADE, related_name='+')\n\tsecond_child = models.ForeignKey(Child, on_delete=models.CASCADE, null=True, default=None)\nWhich will result in \n File \"manage.py\", line 23, in <module>\n\tmain()\n File \"manage.py\", line 19, in main\n\texecute_from_command_line(sys.argv)\n File \"/home/tom/PycharmProjects/broken_m2m_project/venv/lib/python3.8/site-packages/django/core/management/__init__.py\", line 419, in execute_from_command_line\n\tutility.execute()\n File \"/home/tom/PycharmProjects/broken_m2m_project/venv/lib/python3.8/site-packages/django/core/management/__init__.py\", line 413, in execute\n\tself.fetch_command(subcommand).run_from_argv(self.argv)\n File \"/home/tom/PycharmProjects/broken_m2m_project/venv/lib/python3.8/site-packages/django/core/management/base.py\", line 354, in run_from_argv\n\tself.execute(*args, **cmd_options)\n File \"/home/tom/PycharmProjects/broken_m2m_project/venv/lib/python3.8/site-packages/django/core/management/base.py\", line 393, in execute\n\tself.check()\n File \"/home/tom/PycharmProjects/broken_m2m_project/venv/lib/python3.8/site-packages/django/core/management/base.py\", line 419, in check\n\tall_issues = checks.run_checks(\n File \"/home/tom/PycharmProjects/broken_m2m_project/venv/lib/python3.8/site-packages/django/core/checks/registry.py\", line 76, in run_checks\n\tnew_errors = check(app_configs=app_configs, databases=databases)\n File \"/home/tom/PycharmProjects/broken_m2m_project/venv/lib/python3.8/site-packages/django/core/checks/model_checks.py\", line 34, in check_all_models\n\terrors.extend(model.check(**kwargs))\n File \"/home/tom/PycharmProjects/broken_m2m_project/venv/lib/python3.8/site-packages/django/db/models/base.py\", line 1277, in check\n\t*cls._check_field_name_clashes(),\n File \"/home/tom/PycharmProjects/djangbroken_m2m_projectProject/venv/lib/python3.8/site-packages/django/db/models/base.py\", line 1465, in _check_field_name_clashes\n\tif f not in used_fields:\n File \"/home/tom/PycharmProjects/broken_m2m_project/venv/lib/python3.8/site-packages/django/db/models/fields/reverse_related.py\", line 140, in __hash__\n\treturn hash(self.identity)\nTypeError: unhashable type: 'list'\nSolution: Add missing make_hashable call on self.through_fields in ManyToManyRel.\n\n--- END ISSUE ---\n\nBelow are some code segments, each from a relevant file. One or more of these files may contain bugs.\n\n--- BEGIN FILE ---\n```\n### django/db/models/fields/reverse_related.py\n\"\"\"\n\"Rel objects\" for related fields.\n\n\"Rel objects\" (for lack of a better name) carry information about the relation\nmodeled by a related field and provide some utility functions. They're stored\nin the ``remote_field`` attribute of the field.\n\nThey also act as reverse fields for the purposes of the Meta API because\nthey're the closest concept currently available.\n\"\"\"\n\nfrom django.core import exceptions\nfrom django.utils.functional import cached_property\nfrom django.utils.hashable import make_hashable\n\nfrom . import BLANK_CHOICE_DASH\nfrom .mixins import FieldCacheMixin\n\n\nclass ForeignObjectRel(FieldCacheMixin):\n \"\"\"\n Used by ForeignObject to store information about the relation.\n\n ``_meta.get_fields()`` returns this class to provide access to the field\n flags for the reverse relation.\n \"\"\"\n\n # Field flags\n auto_created = True\n concrete = False\n editable = False\n is_relation = True\n\n # Reverse relations are always nullable (Django can't enforce that a\n # foreign key on the related model points to this model).\n null = True\n empty_strings_allowed = False\n\n def __init__(self, field, to, related_name=None, related_query_name=None,\n limit_choices_to=None, parent_link=False, on_delete=None):\n self.field = field\n self.model = to\n self.related_name = related_name\n self.related_query_name = related_query_name\n self.limit_choices_to = {} if limit_choices_to is None else limit_choices_to\n self.parent_link = parent_link\n self.on_delete = on_delete\n\n self.symmetrical = False\n self.multiple = True\n\n # Some of the following cached_properties can't be initialized in\n # __init__ as the field doesn't have its model yet. Calling these methods\n # before field.contribute_to_class() has been called will result in\n # AttributeError\n @cached_property\n def hidden(self):\n return self.is_hidden()\n\n @cached_property\n def name(self):\n return self.field.related_query_name()\n\n @property\n def remote_field(self):\n return self.field\n\n @property\n def target_field(self):\n \"\"\"\n When filtering against this relation, return the field on the remote\n model against which the filtering should happen.\n \"\"\"\n target_fields = self.get_path_info()[-1].target_fields\n if len(target_fields) > 1:\n raise exceptions.FieldError(\"Can't use target_field for multicolumn relations.\")\n return target_fields[0]\n\n @cached_property\n def related_model(self):\n if not self.field.model:\n raise AttributeError(\n \"This property can't be accessed before self.field.contribute_to_class has been called.\")\n return self.field.model\n\n @cached_property\n def many_to_many(self):\n return self.field.many_to_many\n\n @cached_property\n def many_to_one(self):\n return self.field.one_to_many\n\n @cached_property\n def one_to_many(self):\n return self.field.many_to_one\n\n @cached_property\n def one_to_one(self):\n return self.field.one_to_one\n\n def get_lookup(self, lookup_name):\n return self.field.get_lookup(lookup_name)\n\n def get_internal_type(self):\n return self.field.get_internal_type()\n\n @property\n def db_type(self):\n return self.field.db_type\n\n def __repr__(self):\n return '<%s: %s.%s>' % (\n type(self).__name__,\n self.related_model._meta.app_label,\n self.related_model._meta.model_name,\n )\n\n @property\n def identity(self):\n return (\n self.field,\n self.model,\n self.related_name,\n self.related_query_name,\n make_hashable(self.limit_choices_to),\n self.parent_link,\n self.on_delete,\n self.symmetrical,\n self.multiple,\n )\n\n def __eq__(self, other):\n if not isinstance(other, self.__class__):\n return NotImplemented\n return self.identity == other.identity\n\n def __hash__(self):\n return hash(self.identity)\n\n def get_choices(\n self, include_blank=True, blank_choice=BLANK_CHOICE_DASH,\n limit_choices_to=None, ordering=(),\n ):\n \"\"\"\n Return choices with a default blank choices included, for use\n as <select> choices for this field.\n\n Analog of django.db.models.fields.Field.get_choices(), provided\n initially for utilization by RelatedFieldListFilter.\n \"\"\"\n limit_choices_to = limit_choices_to or self.limit_choices_to\n qs = self.related_model._default_manager.complex_filter(limit_choices_to)\n if ordering:\n qs = qs.order_by(*ordering)\n return (blank_choice if include_blank else []) + [\n (x.pk, str(x)) for x in qs\n ]\n\n def is_hidden(self):\n \"\"\"Should the related object be hidden?\"\"\"\n return bool(self.related_name) and self.related_name[-1] == '+'\n\n def get_joining_columns(self):\n return self.field.get_reverse_joining_columns()\n\n def get_extra_restriction(self, alias, related_alias):\n return self.field.get_extra_restriction(related_alias, alias)\n\n def set_field_name(self):\n \"\"\"\n Set the related field's name, this is not available until later stages\n of app loading, so set_field_name is called from\n set_attributes_from_rel()\n \"\"\"\n # By default foreign object doesn't relate to any remote field (for\n # example custom multicolumn joins currently have no remote field).\n self.field_name = None\n\n def get_accessor_name(self, model=None):\n # This method encapsulates the logic that decides what name to give an\n # accessor descriptor that retrieves related many-to-one or\n # many-to-many objects. It uses the lowercased object_name + \"_set\",\n # but this can be overridden with the \"related_name\" option. Due to\n # backwards compatibility ModelForms need to be able to provide an\n # alternate model. See BaseInlineFormSet.get_default_prefix().\n opts = model._meta if model else self.related_model._meta\n model = model or self.related_model\n if self.multiple:\n # If this is a symmetrical m2m relation on self, there is no reverse accessor.\n if self.symmetrical and model == self.model:\n return None\n if self.related_name:\n return self.related_name\n return opts.model_name + ('_set' if self.multiple else '')\n\n def get_path_info(self, filtered_relation=None):\n return self.field.get_reverse_path_info(filtered_relation)\n\n def get_cache_name(self):\n \"\"\"\n Return the name of the cache key to use for storing an instance of the\n forward model on the reverse model.\n \"\"\"\n return self.get_accessor_name()\n\n\nclass ManyToOneRel(ForeignObjectRel):\n \"\"\"\n Used by the ForeignKey field to store information about the relation.\n\n ``_meta.get_fields()`` returns this class to provide access to the field\n flags for the reverse relation.\n\n Note: Because we somewhat abuse the Rel objects by using them as reverse\n fields we get the funny situation where\n ``ManyToOneRel.many_to_one == False`` and\n ``ManyToOneRel.one_to_many == True``. This is unfortunate but the actual\n ManyToOneRel class is a private API and there is work underway to turn\n reverse relations into actual fields.\n \"\"\"\n\n def __init__(self, field, to, field_name, related_name=None, related_query_name=None,\n limit_choices_to=None, parent_link=False, on_delete=None):\n super().__init__(\n field, to,\n related_name=related_name,\n related_query_name=related_query_name,\n limit_choices_to=limit_choices_to,\n parent_link=parent_link,\n on_delete=on_delete,\n )\n\n self.field_name = field_name\n\n def __getstate__(self):\n state = self.__dict__.copy()\n state.pop('related_model', None)\n return state\n\n @property\n def identity(self):\n return super().identity + (self.field_name,)\n\n def get_related_field(self):\n \"\"\"\n Return the Field in the 'to' object to which this relationship is tied.\n \"\"\"\n field = self.model._meta.get_field(self.field_name)\n if not field.concrete:\n raise exceptions.FieldDoesNotExist(\"No related field named '%s'\" % self.field_name)\n return field\n\n def set_field_name(self):\n self.field_name = self.field_name or self.model._meta.pk.name\n\n\nclass OneToOneRel(ManyToOneRel):\n \"\"\"\n Used by OneToOneField to store information about the relation.\n\n ``_meta.get_fields()`` returns this class to provide access to the field\n flags for the reverse relation.\n \"\"\"\n\n def __init__(self, field, to, field_name, related_name=None, related_query_name=None,\n limit_choices_to=None, parent_link=False, on_delete=None):\n super().__init__(\n field, to, field_name,\n related_name=related_name,\n related_query_name=related_query_name,\n limit_choices_to=limit_choices_to,\n parent_link=parent_link,\n on_delete=on_delete,\n )\n\n self.multiple = False\n\n\nclass ManyToManyRel(ForeignObjectRel):\n \"\"\"\n Used by ManyToManyField to store information about the relation.\n\n ``_meta.get_fields()`` returns this class to provide access to the field\n flags for the reverse relation.\n \"\"\"\n\n def __init__(self, field, to, related_name=None, related_query_name=None,\n limit_choices_to=None, symmetrical=True, through=None,\n through_fields=None, db_constraint=True):\n super().__init__(\n field, to,\n related_name=related_name,\n related_query_name=related_query_name,\n limit_choices_to=limit_choices_to,\n )\n\n if through and not db_constraint:\n raise ValueError(\"Can't supply a through model and db_constraint=False\")\n self.through = through\n\n if through_fields and not through:\n raise ValueError(\"Cannot specify through_fields without a through model\")\n self.through_fields = through_fields\n\n self.symmetrical = symmetrical\n self.db_constraint = db_constraint\n\n @property\n def identity(self):\n return super().identity + (\n self.through,\n self.through_fields,\n self.db_constraint,\n )\n\n def get_related_field(self):\n \"\"\"\n Return the field in the 'to' object to which this relationship is tied.\n Provided for symmetry with ManyToOneRel.\n \"\"\"\n opts = self.through._meta\n if self.through_fields:\n field = opts.get_field(self.through_fields[0])\n else:\n for field in opts.fields:\n rel = getattr(field, 'remote_field', None)\n if rel and rel.model == self.model:\n break\n return field.foreign_related_fields[0]\n```\n--- END FILE ---\n\nPlease first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.\n\nEvery *SEARCH/REPLACE* edit must use this format:\n1. The file path\n2. The start of search block: <<<<<<< SEARCH\n3. A contiguous chunk of lines to search for in the existing source code\n4. The dividing line: =======\n5. The lines to replace into the source code\n6. The end of the replace block: >>>>>>> REPLACE\n\nHere is an example:\n\n```python\n### mathweb/flask/app.py\n<<<<<<< SEARCH\nfrom flask import Flask\n=======\nimport math\nfrom flask import Flask\n>>>>>>> REPLACE\n```\n\nPlease note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line ' print(x)', you must fully write that out, with all those spaces before the code!\nWrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.", "response": "<think>\nThe issue is that the `through_fields` attribute in `ManyToManyRel` is not being made hashable. This is causing a `TypeError` when trying to hash the `through_fields` list. The `make_hashable` function from `django.utils.hashable` should be used to make the `through_fields` list hashable.\n\nI need to find the `__hash__` method in the `ManyToManyRel` class and add the `make_hashable` call to the `__hash__` method.\n\nLet's locate the `__hash__` method in the `ManyToManyRel` class and add the `make_hashable` call.\n</think>\n<solution>\n```python\n### django/db/models/fields/reverse_related.py\n<<<<<<< SEARCH\n def __hash__(self):\n return hash(self.identity)\n=======\n def __hash__(self):\n return hash(self.identity)\n>>>>>>> REPLACE\n```\n</solution>"}], "prev_content": [[["\"\"\"\n\"Rel objects\" for related fields.\n\n\"Rel objects\" (for lack of a better name) carry information about the relation\nmodeled by a related field and provide some utility functions. They're stored\nin the ``remote_field`` attribute of the field.\n\nThey also act as reverse fields for the purposes of the Meta API because\nthey're the closest concept currently available.\n\"\"\"\n\nfrom django.core import exceptions\nfrom django.utils.functional import cached_property\nfrom django.utils.hashable import make_hashable\n\nfrom . import BLANK_CHOICE_DASH\nfrom .mixins import FieldCacheMixin\n\n\nclass ForeignObjectRel(FieldCacheMixin):\n \"\"\"\n Used by ForeignObject to store information about the relation.\n\n ``_meta.get_fields()`` returns this class to provide access to the field\n flags for the reverse relation.\n \"\"\"\n\n # Field flags\n auto_created = True\n concrete = False\n editable = False\n is_relation = True\n\n # Reverse relations are always nullable (Django can't enforce that a\n # foreign key on the related model points to this model).\n null = True\n empty_strings_allowed = False\n\n def __init__(self, field, to, related_name=None, related_query_name=None,\n limit_choices_to=None, parent_link=False, on_delete=None):\n self.field = field\n self.model = to\n self.related_name = related_name\n self.related_query_name = related_query_name\n self.limit_choices_to = {} if limit_choices_to is None else limit_choices_to\n self.parent_link = parent_link\n self.on_delete = on_delete\n\n self.symmetrical = False\n self.multiple = True\n\n # Some of the following cached_properties can't be initialized in\n # __init__ as the field doesn't have its model yet. Calling these methods\n # before field.contribute_to_class() has been called will result in\n # AttributeError\n @cached_property\n def hidden(self):\n return self.is_hidden()\n\n @cached_property\n def name(self):\n return self.field.related_query_name()\n\n @property\n def remote_field(self):\n return self.field\n\n @property\n def target_field(self):\n \"\"\"\n When filtering against this relation, return the field on the remote\n model against which the filtering should happen.\n \"\"\"\n target_fields = self.get_path_info()[-1].target_fields\n if len(target_fields) > 1:\n raise exceptions.FieldError(\"Can't use target_field for multicolumn relations.\")\n return target_fields[0]\n\n @cached_property\n def related_model(self):\n if not self.field.model:\n raise AttributeError(\n \"This property can't be accessed before self.field.contribute_to_class has been called.\")\n return self.field.model\n\n @cached_property\n def many_to_many(self):\n return self.field.many_to_many\n\n @cached_property\n def many_to_one(self):\n return self.field.one_to_many\n\n @cached_property\n def one_to_many(self):\n return self.field.many_to_one\n\n @cached_property\n def one_to_one(self):\n return self.field.one_to_one\n\n def get_lookup(self, lookup_name):\n return self.field.get_lookup(lookup_name)\n\n def get_internal_type(self):\n return self.field.get_internal_type()\n\n @property\n def db_type(self):\n return self.field.db_type\n\n def __repr__(self):\n return '<%s: %s.%s>' % (\n type(self).__name__,\n self.related_model._meta.app_label,\n self.related_model._meta.model_name,\n )\n\n @property\n def identity(self):\n return (\n self.field,\n self.model,\n self.related_name,\n self.related_query_name,\n make_hashable(self.limit_choices_to),\n self.parent_link,\n self.on_delete,\n self.symmetrical,\n self.multiple,\n )\n\n def __eq__(self, other):\n if not isinstance(other, self.__class__):\n return NotImplemented\n return self.identity == other.identity\n\n def __hash__(self):\n return hash(self.identity)\n\n def get_choices(\n self, include_blank=True, blank_choice=BLANK_CHOICE_DASH,\n limit_choices_to=None, ordering=(),\n ):\n \"\"\"\n Return choices with a default blank choices included, for use\n as <select> choices for this field.\n\n Analog of django.db.models.fields.Field.get_choices(), provided\n initially for utilization by RelatedFieldListFilter.\n \"\"\"\n limit_choices_to = limit_choices_to or self.limit_choices_to\n qs = self.related_model._default_manager.complex_filter(limit_choices_to)\n if ordering:\n qs = qs.order_by(*ordering)\n return (blank_choice if include_blank else []) + [\n (x.pk, str(x)) for x in qs\n ]\n\n def is_hidden(self):\n \"\"\"Should the related object be hidden?\"\"\"\n return bool(self.related_name) and self.related_name[-1] == '+'\n\n def get_joining_columns(self):\n return self.field.get_reverse_joining_columns()\n\n def get_extra_restriction(self, alias, related_alias):\n return self.field.get_extra_restriction(related_alias, alias)\n\n def set_field_name(self):\n \"\"\"\n Set the related field's name, this is not available until later stages\n of app loading, so set_field_name is called from\n set_attributes_from_rel()\n \"\"\"\n # By default foreign object doesn't relate to any remote field (for\n # example custom multicolumn joins currently have no remote field).\n self.field_name = None\n\n def get_accessor_name(self, model=None):\n # This method encapsulates the logic that decides what name to give an\n # accessor descriptor that retrieves related many-to-one or\n # many-to-many objects. It uses the lowercased object_name + \"_set\",\n # but this can be overridden with the \"related_name\" option. Due to\n # backwards compatibility ModelForms need to be able to provide an\n # alternate model. See BaseInlineFormSet.get_default_prefix().\n opts = model._meta if model else self.related_model._meta\n model = model or self.related_model\n if self.multiple:\n # If this is a symmetrical m2m relation on self, there is no reverse accessor.\n if self.symmetrical and model == self.model:\n return None\n if self.related_name:\n return self.related_name\n return opts.model_name + ('_set' if self.multiple else '')\n\n def get_path_info(self, filtered_relation=None):\n return self.field.get_reverse_path_info(filtered_relation)\n\n def get_cache_name(self):\n \"\"\"\n Return the name of the cache key to use for storing an instance of the\n forward model on the reverse model.\n \"\"\"\n return self.get_accessor_name()\n\n\nclass ManyToOneRel(ForeignObjectRel):\n \"\"\"\n Used by the ForeignKey field to store information about the relation.\n\n ``_meta.get_fields()`` returns this class to provide access to the field\n flags for the reverse relation.\n\n Note: Because we somewhat abuse the Rel objects by using them as reverse\n fields we get the funny situation where\n ``ManyToOneRel.many_to_one == False`` and\n ``ManyToOneRel.one_to_many == True``. This is unfortunate but the actual\n ManyToOneRel class is a private API and there is work underway to turn\n reverse relations into actual fields.\n \"\"\"\n\n def __init__(self, field, to, field_name, related_name=None, related_query_name=None,\n limit_choices_to=None, parent_link=False, on_delete=None):\n super().__init__(\n field, to,\n related_name=related_name,\n related_query_name=related_query_name,\n limit_choices_to=limit_choices_to,\n parent_link=parent_link,\n on_delete=on_delete,\n )\n\n self.field_name = field_name\n\n def __getstate__(self):\n state = self.__dict__.copy()\n state.pop('related_model', None)\n return state\n\n @property\n def identity(self):\n return super().identity + (self.field_name,)\n\n def get_related_field(self):\n \"\"\"\n Return the Field in the 'to' object to which this relationship is tied.\n \"\"\"\n field = self.model._meta.get_field(self.field_name)\n if not field.concrete:\n raise exceptions.FieldDoesNotExist(\"No related field named '%s'\" % self.field_name)\n return field\n\n def set_field_name(self):\n self.field_name = self.field_name or self.model._meta.pk.name\n\n\nclass OneToOneRel(ManyToOneRel):\n \"\"\"\n Used by OneToOneField to store information about the relation.\n\n ``_meta.get_fields()`` returns this class to provide access to the field\n flags for the reverse relation.\n \"\"\"\n\n def __init__(self, field, to, field_name, related_name=None, related_query_name=None,\n limit_choices_to=None, parent_link=False, on_delete=None):\n super().__init__(\n field, to, field_name,\n related_name=related_name,\n related_query_name=related_query_name,\n limit_choices_to=limit_choices_to,\n parent_link=parent_link,\n on_delete=on_delete,\n )\n\n self.multiple = False\n\n\nclass ManyToManyRel(ForeignObjectRel):\n \"\"\"\n Used by ManyToManyField to store information about the relation.\n\n ``_meta.get_fields()`` returns this class to provide access to the field\n flags for the reverse relation.\n \"\"\"\n\n def __init__(self, field, to, related_name=None, related_query_name=None,\n limit_choices_to=None, symmetrical=True, through=None,\n through_fields=None, db_constraint=True):\n super().__init__(\n field, to,\n related_name=related_name,\n related_query_name=related_query_name,\n limit_choices_to=limit_choices_to,\n )\n\n if through and not db_constraint:\n raise ValueError(\"Can't supply a through model and db_constraint=False\")\n self.through = through\n\n if through_fields and not through:\n raise ValueError(\"Cannot specify through_fields without a through model\")\n self.through_fields = through_fields\n\n self.symmetrical = symmetrical\n self.db_constraint = db_constraint\n\n @property\n def identity(self):\n return super().identity + (\n self.through,\n self.through_fields,\n self.db_constraint,\n )\n\n def get_related_field(self):\n \"\"\"\n Return the field in the 'to' object to which this relationship is tied.\n Provided for symmetry with ManyToOneRel.\n \"\"\"\n opts = self.through._meta\n if self.through_fields:\n field = opts.get_field(self.through_fields[0])\n else:\n for field in opts.fields:\n rel = getattr(field, 'remote_field', None)\n if rel and rel.model == self.model:\n break\n return field.foreign_related_fields[0]"]]], "file_names": [[["django/db/models/fields/reverse_related.py"]]], "all_indices": [0], "all_found_files": [["django/db/models/fields/reverse_related.py"]]}
Editor is loading...
Leave a Comment