[1.2.X] Fixed #3055 -- Validate that models target of a GenericRelation have a GenericForeignKey field.

Thanks jason for diagnosing the problem and Marcos Moyano for the patch.

Backport of [14563] from trunk

git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.2.X@14565 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Ramiro Morales 2010-11-14 23:36:40 +00:00
parent dc3b524f6c
commit 2f91f76417
3 changed files with 36 additions and 0 deletions

View File

@ -1,7 +1,14 @@
import sys import sys
from django.contrib.contenttypes.generic import GenericForeignKey, GenericRelation
from django.core.management.color import color_style from django.core.management.color import color_style
from django.utils.itercompat import is_iterable from django.utils.itercompat import is_iterable
try:
any
except NameError:
from django.utils.itercompat import any
class ModelErrorCollection: class ModelErrorCollection:
def __init__(self, outfile=sys.stdout): def __init__(self, outfile=sys.stdout):
self.errors = [] self.errors = []
@ -216,6 +223,12 @@ def get_validation_errors(outfile, app=None):
e.add(opts, "'%s' specifies an m2m relation through model %s, " e.add(opts, "'%s' specifies an m2m relation through model %s, "
"which has not been installed" % (f.name, f.rel.through) "which has not been installed" % (f.name, f.rel.through)
) )
elif isinstance(f, GenericRelation):
if not any([isinstance(vfield, GenericForeignKey) for vfield in f.rel.to._meta.virtual_fields]):
e.add(opts, "Model '%s' must have a GenericForeignKey in "
"order to create a GenericRelation that points to it."
% f.rel.to.__name__
)
rel_opts = f.rel.to._meta rel_opts = f.rel.to._meta
rel_name = RelatedObject(f.rel.to, cls, f).get_accessor_name() rel_name = RelatedObject(f.rel.to, cls, f).get_accessor_name()

View File

@ -37,3 +37,9 @@ def all(iterable):
if not item: if not item:
return False return False
return True return True
def any(iterable):
for item in iterable:
if item:
return True
return False

View File

@ -4,6 +4,7 @@
This example exists purely to point out errors in models. This example exists purely to point out errors in models.
""" """
from django.contrib.contenttypes import generic
from django.db import models from django.db import models
class FieldErrors(models.Model): class FieldErrors(models.Model):
@ -210,6 +211,21 @@ class NonExistingOrderingWithSingleUnderscore(models.Model):
class Meta: class Meta:
ordering = ("does_not_exist",) ordering = ("does_not_exist",)
class Tag(models.Model):
name = models.CharField("name", max_length=20)
class TaggedObject(models.Model):
object_id = models.PositiveIntegerField("Object ID")
tag = models.ForeignKey(Tag)
content_object = generic.GenericForeignKey()
class UserTaggedObject(models.Model):
object_tag = models.ForeignKey(TaggedObject)
class ArticleAttachment(models.Model):
tags = generic.GenericRelation(TaggedObject)
user_tags = generic.GenericRelation(UserTaggedObject)
model_errors = """invalid_models.fielderrors: "charfield": CharFields require a "max_length" attribute that is a positive integer. model_errors = """invalid_models.fielderrors: "charfield": CharFields require a "max_length" attribute that is a positive integer.
invalid_models.fielderrors: "charfield2": CharFields require a "max_length" attribute that is a positive integer. invalid_models.fielderrors: "charfield2": CharFields require a "max_length" attribute that is a positive integer.
invalid_models.fielderrors: "charfield3": CharFields require a "max_length" attribute that is a positive integer. invalid_models.fielderrors: "charfield3": CharFields require a "max_length" attribute that is a positive integer.
@ -315,4 +331,5 @@ invalid_models.uniquem2m: ManyToManyFields cannot be unique. Remove the unique
invalid_models.nonuniquefktarget1: Field 'bad' under model 'FKTarget' must have a unique=True constraint. invalid_models.nonuniquefktarget1: Field 'bad' under model 'FKTarget' must have a unique=True constraint.
invalid_models.nonuniquefktarget2: Field 'bad' under model 'FKTarget' must have a unique=True constraint. invalid_models.nonuniquefktarget2: Field 'bad' under model 'FKTarget' must have a unique=True constraint.
invalid_models.nonexistingorderingwithsingleunderscore: "ordering" refers to "does_not_exist", a field that doesn't exist. invalid_models.nonexistingorderingwithsingleunderscore: "ordering" refers to "does_not_exist", a field that doesn't exist.
invalid_models.articleattachment: Model 'UserTaggedObject' must have a GenericForeignKey in order to create a GenericRelation that points to it.
""" """