Imagine we have this class:
class Custom:
@classmethod
def get_choices(cls):
# use cls attributes to return a list
mapping = {"key": ... }
I would like to associate the value returned by get_choices() to key. What code should go instead of the placeholder ... ?
EDIT: I wanted to keep the question context-agnostic (it seemed to me that this requirement was common enough, but I could be biased). As was suggested in comments, I will give some more details, because it seems we share the concern of 'most straightforward code':
I am working on a Django application, where I want to keep enumeration of values separated of the Models using them. What seemed to me like a natural solution was to create an enumeration.py module, where I could then define a class for each enumeration (the class having at least a class method to generate the collection of values). This is the get_choices() in the example.
Now, because of business logic, I need to map those choices to a key. This mapping being logically coupled to the enumeration, it seemed like a good structure to keep them together, in the same class (giving client code uniform and explicit access, being prefixed by the class name).
解决方案
You cannot do it in class definition because class object has not been created yet.
After the class definition, you could definitely do something like this -
Custom.mapping['key'] = Custom.get_choices()
Although the recommended way to do this would be to use a metaclass.
class CustomMetaClass(type):
def __init__(cls, classname, bases, attrs):
super(CustomMetaClass, cls).__init__(classname, bases, attrs)
cls.mapping['key'] = cls.get_choices()
class Custom(metaclass = CustomMetaClass): # assuming you are using python 3
mapping = {}
@classmethod
def get_choices(cls):
# add your custom code here
pass
With that said, that is an Object Oriented solution to the problem. you can ofcourse use some function to generate choices thus ending the need to use metaclass.
For Edited Question:-
In that case, I think you should just maintain a file named 'choices.py' as you yourself suggested and use them in your mapping, instead of get_choices class method. You don't need to unnecessarily make classes for each model if all you want to do is store choices. Just use dicts and constants.
If your classes needs to be generated dynamically, say from db, then you need to create separate model for storing choices.
class CustomModelChoices(models.Model):
model_name = models.StringField(db_field = 'mn')
choices = models.DictField(db_field = 'ch')
class CustomModel(models.Model):
_choice_generator = CustomModelChoices
mapping = {
'key': CustomModelChoices.objects.get(model_name = 'CustomModel').choices
}
This is just a raw design, might need to be improved a lot, but something on these lines.