Package: django-register-field
django-register-fieldA field that returns a python object.InstallationTo install, callpip install django-register-field.UsageThe RegisterField allows storing specific objects in the database and retriving them directly from the model. The will be stored as strings, with a Register that is used to keep track of which string maps to what object. It cannot be used to store objects dynamically, but can be very useful to separate some logic into their related classes, reducing the number of if/else required in the model methods.There are 2 ways to implement the fields: through the RegisterChoices, or by manually implementing the register. The former makes it easy to implement and use, the latter offers more flexibility.RegisterChoicesThe implementation of the RegisterChoices is very similar to django's default Choices, but even simpler. It looks like this:fromdataclassesimportdataclassfromdjango_registerimportRegisterChoices@dataclass(unsafe_hash=True)classMyOptions:some_field:strsome_description:strclassSomeRegisterChoices(RegisterChoices):OPTION_1=MyOptions(some_field='field_name',some_description='field_description')OPTION_2=MyOptions(some_field='field_name_2',some_description='field_description_2')SomeRegisterChoicesis now usable in a RegisterField on a model:fromdjango_registerimportRegisterFieldclassSomeModel(models.Model):my_field=RegisterField(choices=SomeRegisterChoices)Note that the objects passed to RegisterChoices must be hashable. This is because the register keeps track of the relationship between the label and the object in both directions, so the object needs to be usable as a key in a dictionary.By default, the label used in the database will be the same as the variable name on the choices, in lower case. This can be changed by having alabelattribute on the object. If one is set, that is what will be used database side. Similarly, the verbose field used in the.choicesto be displayed in django admin will be the variable name with all underscores replaced by a space, and.titleapplied to it. This can be changed by setting theverbose_nameattribute on the object.In the background, the RegisterChoices takes care of setting and handling the Register for you. You can also create it and set it manually, if using the Choices is not an option.Setting the Register directlyTo set the register manually, you first need to instantiate a Register:fromdjango_registerimportRegisterregister=Register()With that done, you can register objects within yourmodels.pyfile directly.:register.register(some_object,db_key='some_label')db_keyis not required. If not set, thelabelmust be set on the object, otherwise aValueErroris raised. You can then pass the register to theRegisterFielddirectly:fromdjango_registerimportRegisterFieldclassSomeModel(models.Model):my_field=RegisterField(register=register)You can also have it be part of the Model class:fromdjango_registerimportRegisterFieldclassSomeModel(models.Model):register=Register()register.register(some_object,db_key='some_label')my_field=RegisterField(register=register)Note that if using that technique, you are responsible for keeping track of your object. TheRegisterChoicesmake it easier to keep your objects for comparison and use them outside of the model, but both methods will give the same results database side.If you need to set the register values dynamically, you can do so after the fact by using the register directly. However in that case, you need to provide amax_lengthif your database does not support having aCharFieldwithout amax_length. That is because in the background, aCharFieldis used to store the key in the database.You can set the values dynamically like this:classSomeApp(AppConfig):defready(self):register.register(some_object,db_key='some_label')It does not have to be in thereadymethod, values can be added to the register anywhere, however you should be very careful about where you allow adding values and when. If the value is not available somewhere in the code, it will throw aValidationErrorsaying that the value cannot be found in the register.Using with django-rest-frameworkIf using with rest_framework, there is a Serializer Field already built in to be used by the Serializer. You simply need to set the field as such:fromdjango_register.rest_frameworkimportRegisterFieldclassSomeModelSerializer(serializers.ModelSerializer):some_register_field=RegisterField()classMeta:model=SomeModelfields=('some_register_field',)Behind the scenes, the serializer field goes and gets the register from the model field to get the work done.Since v1.0.7, it is now possible to passkeysto the serializer RegisterField to tell it to return an object with those keys. This is useful if you want to expose certain values on the object to the API.It would look something like this:fromdjango_register.rest_frameworkimportRegisterFieldclassSomeModelSerializer(serializers.ModelSerializer):some_register_field=RegisterField(key=['label','some_value','some_other_value'])classMeta:model=SomeModelfields=('some_register_field',)The example above would return the following JSON:{"some_register_field":{"label":"obj_label","some_value":"value","some_other_value":"other_value"}}Note that if thelabelorverbose_nameis not set on the object directly, the default value that is set automatically will be returned, so they can always be used this way.ThanksHuge thanks to Tim Schilling from Better Simple for hisarticlethat was the catalyst behind the idea for this library.