I'm trying to reinstall a site I haven't used in several months and am getting an error I can't seem to find a solution for.
Running the latest trunk of django, python 2.6.
Here is the stack trace:::
[Fri Apr 01 19:31:00 2011] [error] [client X.X.X.X] mod_wsgi (pid=9458): Exception occurred processing WSGI script '/home/www/vhosts/site/site.wsgi'.
[Fri Apr 01 19:31:00 2011] [error] [client X.X.X.X] Traceback (most recent call last):
[Fri Apr 01 19:31:00 2011] [error] [client X.X.X.X] File "/usr/lib/python2.6/site-packages/django/core/handlers/wsgi.py", line 273, in __call__
[Fri Apr 01 19:31:00 2011] [error] [client X.X.X.X] response = self.get_response(request)
[Fri Apr 01 19:31:00 2011] [error] [client X.X.X.X] File "/usr/lib/python2.6/site-packages/django/core/handlers/base.py", line 169, in get_response
[Fri Apr 01 19:31:00 2011] [error] [client X.X.X.X] response = self.handle_uncaught_exception(request, resolver, sys.exc_info())
[Fri Apr 01 19:31:00 2011] [error] [client X.X.X.X] File "/usr/lib/python2.6/site-packages/django/core/handlers/base.py", line 214, in handle_uncaught_exception
[Fri Apr 01 19:31:00 2011] [error] [client X.X.X.X] if resolver.urlconf_module is None:
[Fri Apr 01 19:31:00 2011] [error] [client X.X.X.X] File "/usr/lib/python2.6/site-packages/django/core/urlresolvers.py", line 274, in _get_urlconf_module
[Fri Apr 01 19:31:00 2011] [error] [client X.X.X.X] self._urlconf_module = import_module(self.urlconf_name)
[Fri Apr 01 19:31:00 2011] [error] [client X.X.X.X] File "/usr/lib/python2.6/site-packages/django/utils/importlib.py", line 35, in import_module
[Fri Apr 01 19:31:00 2011] [error] [client X.X.X.X] __import__(name)
[Fri Apr 01 19:31:00 2011] [error] [client X.X.X.X] File "/home/www/vhosts/site.com/site/urls.py", line 7, in <module>
[Fri Apr 01 19:31:00 2011] [error] [client X.X.X.X] from site.feeds import *
[Fri Apr 01 19:31:00 2011] [error] [client X.X.X.X] File "/home/www/vhosts/site.com/site/feeds.py", line 6, in <module>
[Fri Apr 01 19:31:00 2011] [error] [client X.X.X.X] from site.content.models import *
[Fri Apr 01 19:31:00 2011] [error] [client X.X.X.X] File "/home/www/vhosts/site.com/site/content/models.py", line 14, in <module>
[Fri Apr 01 19:31:00 2011] [error] [client X.X.X.X] from site.authors.models import Author
[Fri Apr 01 19:31:00 2011] [error] [client X.X.X.X] File "/home/www/vhosts/site.com/site/authors/models.py", line 11, in <module>
[Fri Apr 01 19:31:00 2011] [error] [client X.X.X.X] class Author(models.Model):
[Fri Apr 01 19:31:00 2011] [error] [client X.X.X.X] File "/usr/lib/python2.6/site-packages/django/db/models/base.py", line 97, in __new__
[Fri Apr 01 19:31:00 2011] [error] [client X.X.X.X] new_class.add_to_class(obj_name, obj)
[Fri Apr 01 19:31:00 2011] [error] [client X.X.X.X] File "/usr/lib/python2.6/site-packages/django/db/models/base.py", line 217, in add_to_class
[Fri Apr 01 19:31:00 2011] [error] [client X.X.X.X] value.contribute_to_class(cls, name)
[Fri Apr 01 19:31:00 2011] [error] [client X.X.X.X] File "/usr/lib/python2.6/site-packages/django/db/models/fields/related.py", line 891, in contribute_to_class
[Fri Apr 01 19:31:00 2011] [error] [client X.X.X.X] super(ForeignKey, self).contribute_to_class(cls, name)
[Fri Apr 01 19:31:00 2011] [error] [client X.X.X.X] File "/usr/lib/python2.6/site-packages/django/db/models/fields/related.py", line 112, in contribute_to_class
[Fri Apr 01 19:31:00 2011] [error] [client X.X.X.X] self.do_related_class(other, cls)
[Fri Apr 01 19:31:00 2011] [error] [client X.X.X.X] File "/usr/lib/python2.6/site-packages/django/db/models/fields/related.py", line 124, in do_related_class
[Fri Apr 01 19:31:00 2011] [error] [client X.X.X.X] self.contribute_to_related_class(other, self.related)
[Fri Apr 01 19:31:00 2011] [error] [client X.X.X.X] File "/home/www/vhosts/site.com/site/utils/nullableforeignkey.py", line 38, in contribute_to_related_class
[Fri Apr 01 19:31:00 2011] [error] [client X.X.X.X] setattr(cls, _original_csb_attr_name, cls._collect_sub_objects)
[Fri Apr 01 19:31:00 2011] [error] [client X.X.X.X] **AttributeError: type object 'User' has no attribute '_collect_sub_objects'**
Here is the file in question ::
from django.db import models, connection
class NullableForeignKey(models.ForeignKey):
"""
Just like a ForeignKey, but when related objects are deleted this object is
*not* deleted. As the name implies, this field is always NULLable.
"""
def __init__(self, *args, **kwargs):
kwargs['null'] = kwargs['blank'] = True
super(NullableForeignKey, self).__init__(*args, **kwargs)
def contribute_to_related_class(self, cls, related):
super(NullableForeignKey, self).contribute_to_related_class(cls, related)
# define a method name to map the original `_collect_sub_objects` method to
_original_csb_attr_name = '_original_collect_sub_objects'
this_field = self
def _new_collect_sub_objects(self, *args, **kwargs):
# NULL out anything related to this object.
qn = connection.ops.quote_name
for related in self._meta.get_all_related_objects():
if isinstance(related.field, this_field.__class__):
table = qn(related.model._meta.db_table)
column = qn(related.field.column)
sql = "UPDATE %s SET %s = NULL WHERE %s = %%s;" % (table, column, column)
connection.cursor().execute(sql, [self.pk])
# Now proceed with collecting sub objects that are still tied via FK
getattr(self, _original_csb_attr_name)(*args, **kwargs)
# monkey patch the related classes _collect_sub_objects method.
# store the original method in an attr named `_original_csb_attr_name`
if not hasattr(cls, _original_csb_attr_name):
setattr(cls, _original_csb_attr_name, cls._collect_sub_objects)
setattr(cls, '_collect_sub_objects', _new_collect_sub_objects)
# Prevent deletion completely if item has related children
from django.db.models import OneToOneField, ObjectDoesNotExist
from django.utils.encoding import StrAndUnicode
from django.utils.translation import ugettext as _
class ForeignKeysExist(StrAndUnicode, Exception):
def __init__(self, parent, child, field):
'''
Arguments:
parent - parent instance (that contains child records)
child - object that have foreign key pointing to the parent instance
field - child instance foreign key field name
'''
self.parent = parent #parent instance
self.child = child #child that has reference to this parent
self.field = field #field in the child class that points to the parent
self.msg = 'Child record %s.%s exists for %s' % (_(child), _(field), _(parent))
super(ForeignKeysExist, self)
def __unicode__(self):
return self.msg
class NoDeleteCascadeMixin(object):
"""
Mixin to prevent deletion of model
if there exists any children
"""
def delete(self):
# Copied sanity test from django.db.models.ModelBase.delete
assert self._get_pk_val() is not None, "%s object can't be deleted because its %s attribute is set to None." % (self._meta.object_name, self._meta.pk.attname)
opts = self._meta
for related in opts.get_all_related_objects():
rel_accessor = related.get_accessor_name()
if isinstance(related, OneToOneField):
try:
o = getattr(self, rel_accessor)
except ObjectDoesNotExist:
pass # No item in one to one
else:
raise ForeignKeysExist(related.parent_model._meta.object_name, opts.object_name, related.field.name)
else:
rel_manager = getattr(self, rel_accessor)
if rel_manager.count():
raise ForeignKeysExist(related.parent_model._meta.object_name, related.model._meta.object_name, related.field.name)
super(NoDeleteCascadeMixin, self).delete()
Looking at the django source code, _collect_sub_objects
was removed somewhere between release 1.2 and 1.3. See the changes
.
Django now has an on_delete
option for ForeignKeys, docs.
ForeignKey.on_delete
When an object referenced by a ForeignKey is deleted, Django by default emulates the behavior of the SQL constraint ON DELETE CASCADE and also deletes the object containing the ForeignKey. This behavior can be overridden by specifying the on_delete argument. For example, if you have a nullable ForeignKey and you want it to be set null when the referenced object is deleted:
user = models.ForeignKey(User, blank=True, null=True, on_delete=models.SET_NULL)
The possible values for on_delete are found in django.db.models:
CASCADE: Cascade deletes; the default.
PROTECT: Prevent deletion of the referenced object by raising django.db.models.ProtectedError, a subclass of django.db.IntegrityError.
SET_NULL: Set the ForeignKey null; this is only possible if null is True.
SET_DEFAULT: Set the ForeignKey to its default value; a default for the ForeignKey must be set.
SET(): Set the ForeignKey to the value passed to SET(), or if a callable is passed in, the result of calling it. In most cases, passing a callable will be necessary to avoid executing queries at the time your models.py is imported:
def get_sentinel_user():
return User.objects.get_or_create(username='deleted')[0]
class MyModel(models.Model):
user = models.ForeignKey(User, on_delete=models.SET(get_sentinel_user))
DO_NOTHING: Take no action. If your database backend enforces referential integrity, this will cause an IntegrityError unless you manually add a SQL ON DELETE constraint to the database field (perhaps using initial sql).