From 393e4822ae3abf19115f4022d208df106b7cff85 Mon Sep 17 00:00:00 2001
From: Clay McClure <clay@daemons.net>
Date: Wed, 14 Mar 2012 15:41:48 -0400
Subject: [PATCH] Fixed model validation when using hidden (+) related_names
on M2M fields
Fixes #15932.
There is a comment in that same ticket about the ORM not working
properly when hidden (+) related_names are used, but that could
be tracked and fixed as a separate ticket. This commit fixes
the validation issue originally reported.
---
django/core/management/validation.py | 6 +-----
.../invalid_models/invalid_models/models.py | 13 +++++++++++++
2 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/django/core/management/validation.py b/django/core/management/validation.py
index 4833337..3038382 100644
a
|
b
|
def get_validation_errors(outfile, app=None):
|
244 | 244 | rel_opts = f.rel.to._meta |
245 | 245 | rel_name = RelatedObject(f.rel.to, cls, f).get_accessor_name() |
246 | 246 | rel_query_name = f.related_query_name() |
247 | | # If rel_name is none, there is no reverse accessor (this only |
248 | | # occurs for symmetrical m2m relations to self). If this is the |
249 | | # case, there are no clashes to check for this field, as there are |
250 | | # no reverse descriptors for this field. |
251 | | if rel_name is not None: |
| 247 | if not f.rel.is_hidden(): |
252 | 248 | for r in rel_opts.fields: |
253 | 249 | if r.name == rel_name: |
254 | 250 | e.add(opts, "Accessor for m2m field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) |
diff --git a/tests/modeltests/invalid_models/invalid_models/models.py b/tests/modeltests/invalid_models/invalid_models/models.py
index ed69fb6..b74f1da 100644
a
|
b
|
class Target(models.Model):
|
30 | 30 | clash2 = models.CharField(max_length=10) |
31 | 31 | |
32 | 32 | clash1_set = models.CharField(max_length=10) |
| 33 | hiddenrelation_set = models.CharField(max_length=10) |
33 | 34 | |
34 | 35 | class Clash1(models.Model): |
35 | 36 | src_safe = models.CharField(max_length=10) |
… |
… |
class Clash2(models.Model):
|
46 | 47 | m2m_1 = models.ManyToManyField(Target, related_name='id') |
47 | 48 | m2m_2 = models.ManyToManyField(Target, related_name='src_safe') |
48 | 49 | |
| 50 | class HiddenRelation(models.Model): |
| 51 | "Hidden relations (related_name[-1] == '+') should not clash" |
| 52 | foreign = models.ForeignKey(Target, related_name='+') |
| 53 | m2m = models.ManyToManyField(Target, related_name='+') |
| 54 | |
| 55 | class MultipleHiddenRelation(models.Model): |
| 56 | "Multiple hidden relations (related_name[-1] == '+') should not clash with each other" |
| 57 | foreign1 = models.ForeignKey(Target, related_name='+') |
| 58 | foreign2 = models.ForeignKey(Target, related_name='+') |
| 59 | m2m1 = models.ManyToManyField(Target, related_name='+') |
| 60 | m2m2 = models.ManyToManyField(Target, related_name='+') |
| 61 | |
49 | 62 | class Target2(models.Model): |
50 | 63 | clash3 = models.CharField(max_length=10) |
51 | 64 | foreign_tgt = models.ForeignKey(Target) |