2007-08-16 14:06:55 +08:00
import sys
from django . core . management . color import color_style
2007-09-15 03:55:24 +08:00
from django . utils . itercompat import is_iterable
2007-08-16 14:06:55 +08:00
class ModelErrorCollection :
def __init__ ( self , outfile = sys . stdout ) :
self . errors = [ ]
self . outfile = outfile
self . style = color_style ( )
def add ( self , context , error ) :
self . errors . append ( ( context , error ) )
self . outfile . write ( self . style . ERROR ( " %s : %s \n " % ( context , error ) ) )
def get_validation_errors ( outfile , app = None ) :
"""
Validates all models that are part of the specified app . If no app name is provided ,
validates all models of all installed apps . Writes errors , if any , to outfile .
Returns number of errors .
"""
from django . conf import settings
from django . db import models , connection
from django . db . models . loading import get_app_errors
from django . db . models . fields . related import RelatedObject
e = ModelErrorCollection ( outfile )
for ( app_name , error ) in get_app_errors ( ) . items ( ) :
e . add ( app_name , error )
for cls in models . get_models ( app ) :
opts = cls . _meta
# Do field-specific validation.
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
for f in opts . local_fields :
2007-08-16 14:06:55 +08:00
if f . name == ' id ' and not f . primary_key and opts . pk . name == ' id ' :
e . add ( opts , ' " %s " : You can \' t use " id " as a field name, because each model automatically gets an " id " field if none of the fields have primary_key=True. You need to either remove/rename your " id " field or add primary_key=True to a field. ' % f . name )
2007-10-22 05:53:18 +08:00
if f . name . endswith ( ' _ ' ) :
e . add ( opts , ' " %s " : Field names cannot end with underscores, because this would lead to ambiguous queryset filters. ' % f . name )
2007-08-16 14:06:55 +08:00
if isinstance ( f , models . CharField ) and f . max_length in ( None , 0 ) :
e . add ( opts , ' " %s " : CharFields require a " max_length " attribute. ' % f . name )
if isinstance ( f , models . DecimalField ) :
if f . decimal_places is None :
e . add ( opts , ' " %s " : DecimalFields require a " decimal_places " attribute. ' % f . name )
if f . max_digits is None :
e . add ( opts , ' " %s " : DecimalFields require a " max_digits " attribute. ' % f . name )
if isinstance ( f , models . FileField ) and not f . upload_to :
e . add ( opts , ' " %s " : FileFields require an " upload_to " attribute. ' % f . name )
if isinstance ( f , models . ImageField ) :
try :
from PIL import Image
except ImportError :
e . add ( opts , ' " %s " : To use ImageFields, you need to install the Python Imaging Library. Get it at http://www.pythonware.com/products/pil/ . ' % f . name )
if f . choices :
2007-09-15 06:49:01 +08:00
if isinstance ( f . choices , basestring ) or not is_iterable ( f . choices ) :
2007-08-16 14:06:55 +08:00
e . add ( opts , ' " %s " : " choices " should be iterable (e.g., a tuple or list). ' % f . name )
else :
for c in f . choices :
if not type ( c ) in ( tuple , list ) or len ( c ) != 2 :
e . add ( opts , ' " %s " : " choices " should be a sequence of two-tuples. ' % f . name )
if f . db_index not in ( None , True , False ) :
e . add ( opts , ' " %s " : " db_index " should be either None, True or False. ' % f . name )
# Check that max_length <= 255 if using older MySQL versions.
if settings . DATABASE_ENGINE == ' mysql ' :
db_version = connection . get_server_version ( )
if db_version < ( 5 , 0 , 3 ) and isinstance ( f , ( models . CharField , models . CommaSeparatedIntegerField , models . SlugField ) ) and f . max_length > 255 :
e . add ( opts , ' " %s " : %s cannot have a " max_length " greater than 255 when you are using a version of MySQL prior to 5.0.3 (you are using %s ). ' % ( f . name , f . __class__ . __name__ , ' . ' . join ( [ str ( n ) for n in db_version [ : 3 ] ] ) ) )
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
# Check to see if the related field will clash with any existing
# fields, m2m fields, m2m related objects or related objects
2007-08-16 14:06:55 +08:00
if f . rel :
if f . rel . to not in models . get_models ( ) :
2007-12-03 02:10:07 +08:00
e . add ( opts , " ' %s ' has relation with model %s , which has not been installed " % ( f . name , f . rel . to ) )
# it is a string and we could not find the model it refers to
# so skip the next section
if isinstance ( f . rel . to , ( str , unicode ) ) :
continue
2007-08-16 14:06:55 +08:00
2007-12-03 02:10:07 +08:00
rel_opts = f . rel . to . _meta
2007-08-16 14:06:55 +08:00
rel_name = RelatedObject ( f . rel . to , cls , f ) . get_accessor_name ( )
rel_query_name = f . related_query_name ( )
for r in rel_opts . fields :
if r . name == rel_name :
e . add ( opts , " Accessor for 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 ) )
if r . name == rel_query_name :
e . add ( opts , " Reverse query name for 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 ) )
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
for r in rel_opts . local_many_to_many :
2007-08-16 14:06:55 +08:00
if r . name == rel_name :
e . add ( opts , " Accessor for field ' %s ' clashes with m2m field ' %s . %s ' . Add a related_name argument to the definition for ' %s ' . " % ( f . name , rel_opts . object_name , r . name , f . name ) )
if r . name == rel_query_name :
e . add ( opts , " Reverse query name for field ' %s ' clashes with m2m field ' %s . %s ' . Add a related_name argument to the definition for ' %s ' . " % ( f . name , rel_opts . object_name , r . name , f . name ) )
for r in rel_opts . get_all_related_many_to_many_objects ( ) :
if r . get_accessor_name ( ) == rel_name :
e . add ( opts , " Accessor for field ' %s ' clashes with related m2m field ' %s . %s ' . Add a related_name argument to the definition for ' %s ' . " % ( f . name , rel_opts . object_name , r . get_accessor_name ( ) , f . name ) )
if r . get_accessor_name ( ) == rel_query_name :
e . add ( opts , " Reverse query name for field ' %s ' clashes with related m2m field ' %s . %s ' . Add a related_name argument to the definition for ' %s ' . " % ( f . name , rel_opts . object_name , r . get_accessor_name ( ) , f . name ) )
for r in rel_opts . get_all_related_objects ( ) :
if r . field is not f :
if r . get_accessor_name ( ) == rel_name :
e . add ( opts , " Accessor for field ' %s ' clashes with related field ' %s . %s ' . Add a related_name argument to the definition for ' %s ' . " % ( f . name , rel_opts . object_name , r . get_accessor_name ( ) , f . name ) )
if r . get_accessor_name ( ) == rel_query_name :
e . add ( opts , " Reverse query name for field ' %s ' clashes with related field ' %s . %s ' . Add a related_name argument to the definition for ' %s ' . " % ( f . name , rel_opts . object_name , r . get_accessor_name ( ) , f . name ) )
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
for i , f in enumerate ( opts . local_many_to_many ) :
2007-08-16 14:06:55 +08:00
# Check to see if the related m2m field will clash with any
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
# existing fields, m2m fields, m2m related objects or related
# objects
2007-08-16 14:06:55 +08:00
if f . rel . to not in models . get_models ( ) :
2007-12-03 02:10:07 +08:00
e . add ( opts , " ' %s ' has m2m relation with model %s , which has not been installed " % ( f . name , f . rel . to ) )
# it is a string and we could not find the model it refers to
# so skip the next section
if isinstance ( f . rel . to , ( str , unicode ) ) :
continue
2007-08-16 14:06:55 +08:00
2007-12-03 02:10:07 +08:00
rel_opts = f . rel . to . _meta
2007-08-16 14:06:55 +08:00
rel_name = RelatedObject ( f . rel . to , cls , f ) . get_accessor_name ( )
rel_query_name = f . related_query_name ( )
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
# If rel_name is none, there is no reverse accessor (this only
# occurs for symmetrical m2m relations to self). If this is the
# case, there are no clashes to check for this field, as there are
# no reverse descriptors for this field.
2007-08-16 14:06:55 +08:00
if rel_name is not None :
for r in rel_opts . fields :
if r . name == rel_name :
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 ) )
if r . name == rel_query_name :
e . add ( opts , " Reverse query name 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 ) )
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
for r in rel_opts . local_many_to_many :
2007-08-16 14:06:55 +08:00
if r . name == rel_name :
e . add ( opts , " Accessor for m2m field ' %s ' clashes with m2m field ' %s . %s ' . Add a related_name argument to the definition for ' %s ' . " % ( f . name , rel_opts . object_name , r . name , f . name ) )
if r . name == rel_query_name :
e . add ( opts , " Reverse query name for m2m field ' %s ' clashes with m2m field ' %s . %s ' . Add a related_name argument to the definition for ' %s ' . " % ( f . name , rel_opts . object_name , r . name , f . name ) )
for r in rel_opts . get_all_related_many_to_many_objects ( ) :
if r . field is not f :
if r . get_accessor_name ( ) == rel_name :
e . add ( opts , " Accessor for m2m field ' %s ' clashes with related m2m field ' %s . %s ' . Add a related_name argument to the definition for ' %s ' . " % ( f . name , rel_opts . object_name , r . get_accessor_name ( ) , f . name ) )
if r . get_accessor_name ( ) == rel_query_name :
e . add ( opts , " Reverse query name for m2m field ' %s ' clashes with related m2m field ' %s . %s ' . Add a related_name argument to the definition for ' %s ' . " % ( f . name , rel_opts . object_name , r . get_accessor_name ( ) , f . name ) )
for r in rel_opts . get_all_related_objects ( ) :
if r . get_accessor_name ( ) == rel_name :
e . add ( opts , " Accessor for m2m field ' %s ' clashes with related field ' %s . %s ' . Add a related_name argument to the definition for ' %s ' . " % ( f . name , rel_opts . object_name , r . get_accessor_name ( ) , f . name ) )
if r . get_accessor_name ( ) == rel_query_name :
e . add ( opts , " Reverse query name for m2m field ' %s ' clashes with related field ' %s . %s ' . Add a related_name argument to the definition for ' %s ' . " % ( f . name , rel_opts . object_name , r . get_accessor_name ( ) , f . name ) )
# Check ordering attribute.
if opts . ordering :
for field_name in opts . ordering :
if field_name == ' ? ' : continue
if field_name . startswith ( ' - ' ) :
field_name = field_name [ 1 : ]
if opts . order_with_respect_to and field_name == ' _order ' :
continue
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
# Skip ordering in the format field1__field2 (FIXME: checking
# this format would be nice, but it's a little fiddly).
if ' _ ' in field_name :
continue
2007-08-16 14:06:55 +08:00
try :
opts . get_field ( field_name , many_to_many = False )
except models . FieldDoesNotExist :
e . add ( opts , ' " ordering " refers to " %s " , a field that doesn \' t exist. ' % field_name )
# Check unique_together.
for ut in opts . unique_together :
for field_name in ut :
try :
f = opts . get_field ( field_name , many_to_many = True )
except models . FieldDoesNotExist :
e . add ( opts , ' " unique_together " refers to %s , a field that doesn \' t exist. Check your syntax. ' % field_name )
else :
if isinstance ( f . rel , models . ManyToManyRel ) :
e . add ( opts , ' " unique_together " refers to %s . ManyToManyFields are not supported in unique_together. ' % f . name )
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
if f not in opts . local_fields :
e . add ( opts , ' " unique_together " refers to %s . This is not in the same model as the unique_together statement. ' % f . name )
2007-08-16 14:06:55 +08:00
return len ( e . errors )