3 from django.db import models
4 from django.forms.models import model_to_dict
5 from django.core.urlresolvers import reverse
6 from django.forms.models import model_to_dict
7 from django.utils import timezone
8 from django.core.exceptions import PermissionDenied
12 # This is a no-op if observer_disabled is set to 1 in the config file
13 from observer import *
15 print >> sys.stderr, "import of observer failed! printing traceback and disabling observer:"
19 # guard against something failing
20 def notify_observer(*args, **kwargs):
23 # This manager will be inherited by all subclasses because
24 # the core model is abstract.
25 class PlCoreBaseDeletionManager(models.Manager):
26 def get_queryset(self):
27 parent=super(PlCoreBaseDeletionManager, self)
28 if hasattr(parent, "get_queryset"):
29 return parent.get_queryset().filter(deleted=True)
31 return parent.get_query_set().filter(deleted=True)
33 # deprecated in django 1.7 in favor of get_queryset().
34 def get_query_set(self):
35 return self.get_queryset()
37 # This manager will be inherited by all subclasses because
38 # the core model is abstract.
39 class PlCoreBaseManager(models.Manager):
40 def get_queryset(self):
41 parent=super(PlCoreBaseManager, self)
42 if hasattr(parent, "get_queryset"):
43 return parent.get_queryset().filter(deleted=False)
45 return parent.get_query_set().filter(deleted=False)
47 # deprecated in django 1.7 in favor of get_queryset().
48 def get_query_set(self):
49 return self.get_queryset()
52 # Provides useful methods for computing which objects in a model have
53 # changed. Make sure to do self._initial = self._dict in the __init__
56 # This is broken out of PlCoreBase into a Mixin so the User model can
57 # also make use of it.
61 return model_to_dict(self, fields=[field.name for field in
68 diffs = [(k, (v, d2[k])) for k, v in d1.items() if v != d2[k]]
72 def has_changed(self):
73 return bool(self.diff)
76 def changed_fields(self):
77 return self.diff.keys()
80 def has_field_changed(self, field_name):
81 return field_name in self.diff.keys()
83 def get_field_diff(self, field_name):
84 return self.diff.get(field_name, None)
87 class PlCoreBase(models.Model, DiffModelMixIn):
88 objects = PlCoreBaseManager()
89 deleted_objects = PlCoreBaseDeletionManager()
91 # default values for created and updated are only there to keep evolution
93 created = models.DateTimeField(auto_now_add=True, default=timezone.now)
94 updated = models.DateTimeField(auto_now=True, default=timezone.now)
95 enacted = models.DateTimeField(null=True, default=None)
96 backend_status = models.CharField(max_length=140,
97 default="Provisioning in progress")
98 deleted = models.BooleanField(default=False)
101 # Changing abstract to False would require the managers of subclasses of
102 # PlCoreBase to be customized individually.
106 def __init__(self, *args, **kwargs):
107 super(PlCoreBase, self).__init__(*args, **kwargs)
108 self._initial = self._dict # for DiffModelMixIn
111 def can_update(self, user):
118 def can_update_field(self, user, fieldName):
119 # Give us the opportunity to implement fine-grained permission checking.
120 # Default to True, and let can_update() permit or deny the whole object.
123 def delete(self, *args, **kwds):
124 # so we have something to give the observer
125 purge = kwds.get('purge',False)
126 silent = kwds.get('silent',False)
128 purge = purge or observer_disabled
134 super(PlCoreBase, self).delete(*args, **kwds)
138 self.save(update_fields=['enacted','deleted'], silent=silent)
140 def save(self, *args, **kwargs):
141 # let the user specify silence as either a kwarg or an instance varible
143 if "silent" in kwargs:
144 silent=silent or kwargs.pop("silent")
146 super(PlCoreBase, self).save(*args, **kwargs)
148 # This is a no-op if observer_disabled is set
152 self._initial = self._dict
154 def save_by_user(self, user, *args, **kwds):
155 if not self.can_update(user):
156 raise PermissionDenied("You do not have permission to update %s objects" % self.__class__.__name__)
158 for fieldName in self.changed_fields:
159 if not self.can_update_field(user, fieldName):
160 raise PermissionDenied("You do not have permission to update field %s in object %s" % (fieldName, self.__class__.__name__))
162 self.save(*args, **kwds)
164 def delete_by_user(self, user, *args, **kwds):
165 if not self.can_update(user):
166 raise PermissionDenied("You do not have permission to delete %s objects" % self.__class__.__name__)
167 self.delete(*args, **kwds)
170 def select_by_user(cls, user):
171 # This should be overridden by descendant classes that want to perform
172 # filtering of visible objects by user.
173 return cls.objects.all()