Reputation: 9669
I'm writing a mixin which will allow my Models to be easily translated into a deep dict of values (kind of like .values(), but traversing relationships). The cleanest place to do the definitions of these seems to be in the models themselves, a la:
class Person(models.Model, DeepValues):
name = models.CharField(blank=True, max_length=100)
tribe = models.ForeignKey('Tribes')
class Meta:
schema = {
'name' : str,
'tribe' : {
'name' : str
}
}
Person.objects.all().deep_values() => {
'name' : 'Andrey Fedorov',
'tribe' : {
'name' : 'Mohicans'
}
}
However, Django complains about my including this in class Meta
with:
TypeError: 'class Meta' got invalid attribute(s): schema
(entire stack trace here)
Now, I suppose I could elaborately override this in my mixin, but is there a more elegant way of storing this information?
Upvotes: 48
Views: 19269
Reputation: 1150
To add to the above I have found another way to add custom attributes to a meta-class by simply prefixing the attribute with an underscore (_
). So the above example would work as follows:
class Person(models.Model, DeepValues):
name = models.CharField(blank=True, max_length=100)
tribe = models.ForeignKey('Tribes')
class Meta:
_schema = {
'name' : str,
'tribe' : {
'name' : str
}
}
Upvotes: 0
Reputation: 2437
This works for me for setting extra fields in meta for a Django model.
class Vendor(CustomModel):
def __init__(self, *args, **kwargs):
cls = self.__class__
meta = getattr(cls, '_meta', None)
setattr(meta, 'exclude_logging', ["otp", "is_otp_verified"])
super().__init__(*args, **kwargs)
This exclude_logging
field can be accessed as below.
class CustomModel(models.Model):
objects = UpdateManager()
class Meta:
abstract = True
def save(self, *args, **kwargs):
print(self._meta.exclude_logging)
I hope this solves the problem.
Upvotes: 3
Reputation: 2125
Not a direct answer, but I did not like the idea of adding it in every model where I need it to the options, so I did:
class MyModel(models.Model):
class Meta:
ordering = ["myfield"]
class MyPrefixMeta:
my_value = "Abc"
You could even put this to a abstract model and validate the set class properties in __init__
function or do things like adding a _myprefix_meta
property to the model. So you had your own meta class.
Upvotes: 5
Reputation: 99317
I don't know about elegant, but one pragmatic way is:
import django.db.models.options as options
options.DEFAULT_NAMES = options.DEFAULT_NAMES + ('schema',)
Obviously, this would break if Django ever added a 'schema' attribute of its own. But hey, it's a thought...you could always pick an attribute name which is less likely to clash.
Upvotes: 66