I am trying to add a dynamic Meta attribute to all of my Django models using model inheritance, but I can't get it to work. I have a permission that I want to add to all my models like this:
class ModelA(models.Model):
class Meta:
permisssions =(('view_modela','Can view Model A'),)
class ModelB(models.Model):
class Meta:
permisssions =(('view_modelb','Can view Model B'),)
I tried creating an abstract base class like this:
class CustomModel(models.Model):
def __init__(self, *args, **kwargs):
self._meta.permissions.append(('view_'+self._meta.module_name, u'Can view %s' % self._meta.verbose_name))
super(CustomModel,self).__init__(*args, **kwargs)
class ModelA(CustomModel):
....
class ModelB(CustomModel):
...
but it's not working. Is this the right approach? Because Django uses introspection to construct the Model classes, I'm not sure if adding permissions during the __init__() of the class will even work. With my current implementation every time I access a model instance it appends another tuple of the permissions.
-
Your instinct is right that this won't work. In Django, permissions are stored in the database, which means that:
- they need to be available at the class level when syncdb is run in order to populate the auth_permission table (and your approach requires an instance, which won't be made during syncdb)
- even if you did add it to
_meta.permissionsin__init__, theUserobject wouldn't pick it up in any permission check calls because those consult the permissions table in the DB (and a cache of that table, at that).
What you actually need here is a metaclass... your goal can't be accomplished using inheritance. The metaclass re-writes your
ModelAandModelBclass definitions dynamically before they are defined, thus it doesn't require aModelAinstance, and is available to syncdb. Since Django's models also use metaclasses to build theMetaobject in the first place, the only requirement is that your metaclass must inherit from the same metaclass as Django's models. Here's some sample code:from django.db.models.base import ModelBase class CustomModelMetaClass(ModelBase): def __new__(cls, name, bases, attrs): klas = super(CustomModelMetaClass, cls).__new__(cls, name, bases, attrs) klas._meta.permissions.append(('view_' + klas._meta.module_name, u'Can view %s' % klas._meta.verbose_name)) return klas class ModelA(models.Model): __metaclass__ = CustomModelMetaClass test = models.CharField(max_length=5)Note that permissions in this case will be written only on
syncdb. If you need to change permissions dynamically at run time base on the user, you'll want to provide your own authentication backend. -
Try to use a custom manager:
#create a custom manager class DynTableNameManager(models.Manager): #overwrite all() (example) #provide table_name def all(self, table_name): from django.db import connection cursor = connection.cursor() cursor.execute(""" SELECT id, name FROM %s """ % table_name) result_list = [] for row in cursor.fetchall(): p = self.model(id=row[0], name=row[1]) result_list.append(p) return result_list #cerate a dummy table class DummyTable(models.Model): name = models.CharField ( max_length = 200 ) objects = DynTableNameManager()use like this:
f = DummyTable.objects.all('my_table_name')rexus : i forgot to mention: this only works if your table structure the same for each table.
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.