Package: django-dunder
django-dunderdjango-dunder is an installable app to automatically provide customisable__repr__and__str__for other Django third-party installable apps
and for project apps.On Python 3, it can use__unicode__if present and__str__is missing,
such as apps that work on Python 3, but havent been fully updated.It emits warnings whenever__unicode__is encountered on an active model.
It does this even on Python 2 when the__unicode__is identical to the__str__, providing custom warnings to indicate what
code changes are needed to finish the Python 3 port.The motivation for this app came while consulting forhttps://github.com/viper-development/, which builds apps quickly,
developing custom functionality instead of writing boilerplate code.By default, it will detect and attach to existing models that are using
the default__repr__and__str__.It can be instructed to overwrite the__repr__and__str__of specific
models, useful if the model has dedicated methods, but the output is not
desirable.It will look for primary and unique keys, in an attempt to show the minimum
necessary for the user to recognise the record.Note: On Python 2, it will add a__str__which may emit non-ascii for
model instances containing Unicode values in the fields it decides to
display.  De-select any such models using the settings.  I am willing to
review a PR to add proper Python 2 support, but I will reject any partial
Python 2 support.  I can be convinced to build it to my own standards,
but it isnt sensible to do it in 2020 without a good reason.Installpip install django-dunderAdddjango_dundertoINSTALLED_APPSbeforemodels that need
dunders added.To catch all models missing__str__or__repr__, put it at the top
ofINSTALLED_APPS.To quickly see how it improves the Django admin, installdjango-data-browserin development before and after, and click its "admin" column on
any model that was using the Django default string representation.ConfigureTo disable unicode warnings, setDUNDER_WARN_UNICODE = False.For more control, in yoursettings, toggle these "auto", "force" and
"exclude" settings.To disable the automatic attaching for one or both of__str__and__repr__,
set one ofDUNDER_AUTO = FalseDUNDER_AUTO_REPR = FalseDUNDER_AUTO_STR = FalseDUNDER_COPY_UNICODE = FalseTo force all models to use these methods, useDUNDER_FORCE = True, or
setDUNDER_FORCE_REPRorDUNDER_FORCE_STRtoTrue.To force specific models only,DUNDER_FORCE_REPRandDUNDER_FORCE_STRmay be defined as a list of model labels, e.g.auth.User.When using either auto or force modes, specific models can be excluded
by providing a list of model labels to the exclude settings:DUNDER_REPR_EXCLUDE=['auth.User']DUNDER_STR_EXCLUDE=['myapp.Person']NoteWhen the copying of__unicode__is disabled on Python 3, and the
Django settingDEBUGis also disabled, this app will raiseImproperlyConfiguredif it finds a__unicode__, as it assumes the app
intended for the__unicode__to be used, and running in production with
the default Django__str__would result in incorrect behaviour.
To disable this, re-enable copying of the unicode, or setDUNDER_REJECT_UNICODE = FalseThere is also a Djangocheckfor inactive custom__unicode__, which runs seperately from the model
registration process, so it is safer to use.  It defaults to emit errors,
however it can be set to emit errors, or disabled by setting it toFalse.DUNDER_CHECK_INACTIVE_UNICODE = 'warn'FormattingThe default formatting of__str__and__repr__given below can be modified
globally in the settings.DUNDER_REPR_ATTR_FMT = '{name}={value!r}'DUNDER_REPR_FMT = '{}({})'DUNDER_STR_ATTR_FMT = '{name}={value}'DUNDER_STR_FMT = '<{}: {}>'In addition to standard Python string Formatter syntax, some experimental magic
behind the scenes allows the chaining together of attribute modifiers.
This is only active for the two attribute formatters.  Methods of types are
transparently invoked, and as are builtins.e.g.DUNDER_STR_ATTR_FMT = '{name}={value.round__title}'will apply
round up numbers and apply title case to strings.In addition, there is one extra modifierellipsisthat can be used to truncate
long text fields, appending an...ellipsis.  It defaults to 100 characters.e.g.DUNDER_STR_ATTR_FMT = '{name}={value.round__ellipsis_20}'will apply
round up numbers and shorten strings to at most 20 characters.On CPython, it is possible to add methods to core types using theforbiddenfruitlibrary.  For example, ifdatatype-toolsis installed as directed, with imports insettings.pyor some other early
loading Django code, use()syntax to use method names containing a_.DUNDER_STR_ATTR_FMT = '{name}={value.round__ellipsis_20__format_date()}'When installing custom methods for core types from libraries, be aware they
often reuse existing core methods or builtin names.
In the case ofdatatype-tools, it provides afloat.round()which uses
two significant places by default whileround(float)has zero as default.When building custom methods for core types, avoid using method names
which conflict with Python names or conflict with Django names.  Otherwise
problems likehttps://github.com/havocesp/typext/issues/1arise.Want more?  If you can find the experimental magic, extend it and activate with:DUNDER_WRAPPER_CLASS = 'your_magic.Wrapper'And please submit PRs to add your magic here for others to use.Explicit fieldsTo show specific fields in eitherstr()orrepr(), two extramodel meta optionsare automatically added by django-dunder:fromdjango.dbimportmodelsclassMyModel(models.Model):uuid=models.TextField()first_name=models.TextField()last_name=models.TextField()...Meta:str_fields=('first_name','last_name')repr_fields=('uuid',)Explicit mixinsAlternatively disable auto mode (DUNDER_AUTO = False), and use the
mixins, and set the :fromdjango_dunder.mixinsimportDunderModelclassMyModel(DunderModel):first_name=models.TextField()last_name=models.TextField()...Meta:repr_fields=('first_name','last_name')Adding Meta options can cause exceptions if django-dunders is removed
fromINSTALLED_APPS.To avoid that, usedjsommoExtending to other typesIt should be possible to apply the functionality here to types other than
Django models and instances.  Some other way of identifying the appropriate
classes to patch is need, perhaps with additional configuration.The ultimate solution for CPython-only would be ifits type dunders could be 'curse'd,
especially ifobject.__str__andobject.__repr__could be replaced.Alternativesdjango-dunder is especially useful when a project uses third-party apps
that do not provide these dunder methods that are suitable for the project.
In fact, severaldjango.contribmodels do not provide these dunder methods.Inspiration was drawn fromdjango-model-reprdjango-auto-reprThey may be sufficient for some projects.If that is not relevant, and if the project is using sentry, and the project
only wants a sane__repr__, incorporate the decorator insentry.db.modelsinto a base mixin model used throughout the project.Starting a new project, and only interested in your own models?pydanticprovides default and customisable
dunders, anddjango-ninjaprovides a Django REST
interface on top, and there are lots of other tools layered on top of pydantic, likepydantic-uiproviding a Django Admin-like
interface.