How to define a Django model field in constant and use everywhere. For example, if I have a model like:-
class Author(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=40)
email = models.EmailField()
And what I want to do is define constant for fields in Author model and provide the constant instead of field name in model like:-
KEY_FIRST_NAME = 'first_name'
KEY_LAST_NAME = 'last_name'
KEY_EMAIL = 'email'
And Author model should use the constant instead of exact key like:-
class Author(models.Model):
KEY_FIRST_NAME = models.CharField(max_length=30)
KEY_LAST_NAME = models.CharField(max_length=40)
KEY_EMAIL = models.EmailField()
How to do something like this, direct assignment to constant won't work here.
I want to store all the field name in constant, and everywhere when it required I want to use the constant instead of string field name.
The purpose of doing this is If there is any change in filed name in future version then I want to only change at one place and it should reflect on all the places.
If it is not possible or it will make code too complex as suggested by one approach by @dirkgroten than what can be the best practice to define the model field as constant and use them in other places (other than inside models like if we are referring those field for admin portal or any other place).
Short answer: you can't do this in Python, period (actually I don't think you could do so in any language but someone will certainly prove me wrong xD).
Now if we go back to your real "problem" - not having to change client code if your model's fields names are ever to change - you'd first need to tell whether you mean "the python attribute name" or "the underlying database field name".
For the second case, the database field name does not have to match the Python attribute name, Django models fields take a db_column
argument to handle this case.
For the first case, I'd have to say that it's a very generic (and not new by any mean) API-design problem, and the usual answer is "you shouldn't change names that are part of your public API once it's been released". Now sh!t happens and sometimes you have to do it. The best solution here is then to use computed attributes redirecting the old name to the new one for the deprecation period and remove them once all the client code has been ported.
An example with your model, changing 'first_name' to 'firstname':
class Author(models.Model):
# assuming the database column name didn't change
# so we can also show how to us `db_column` ;)
firstname = models.CharField(
max_length=30,
db_column='first_name'
)
@property
def first_name(self):
# shoud issue a deprecation warning here
return self.firstname
@first_name.setter
def first_name(self, value):
# shoud issue a deprecation warning here
self.firstname = value
If you have a dozen fields to rename you will certainly want to write a custom descriptor (=> computed attribute) instead to keep it dry:
class Renamed(object):
def __init__(self, new_name):
self.new_name = new_name
def __get__(self, instance, cls):
if instance is None:
return self
# should issue a deprecation warning here
return getattr(instance, self.new_name)
def __set__(self, instance, value):
# should issue a deprecation warning here
setattr(instance, self.new_name, value)
class Author(models.Model):
firstname = models.CharField(
max_length=30,
db_column='first_name'
)
first_name = Renamed("firstname")
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With