Fiexed #3055 -- Validate that models target of a GenericRelation have a GenericForeignKey field.

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

git-svn-id: http://code.djangoproject.com/svn/django/trunk@14563 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Ramiro Morales 2010-11-14 23:21:39 +00:00
parent 0324151bec
commit b6ec268e23
3 changed files with 35 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 = []
@ -224,6 +231,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):
@ -216,6 +217,20 @@ class InvalidSetNull(models.Model):
class InvalidSetDefault(models.Model): class InvalidSetDefault(models.Model):
fk = models.ForeignKey('self', on_delete=models.SET_DEFAULT) fk = models.ForeignKey('self', on_delete=models.SET_DEFAULT)
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.
@ -324,4 +339,5 @@ invalid_models.nonuniquefktarget2: Field 'bad' under model 'FKTarget' must have
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.invalidsetnull: 'fk' specifies on_delete=SET_NULL, but cannot be null. invalid_models.invalidsetnull: 'fk' specifies on_delete=SET_NULL, but cannot be null.
invalid_models.invalidsetdefault: 'fk' specifies on_delete=SET_DEFAULT, but has no default value. invalid_models.invalidsetdefault: 'fk' specifies on_delete=SET_DEFAULT, but has no default value.
invalid_models.articleattachment: Model 'UserTaggedObject' must have a GenericForeignKey in order to create a GenericRelation that points to it.
""" """