Coder Social home page Coder Social logo

jayvdb / django-dunder Goto Github PK

View Code? Open in Web Editor NEW
2.0 4.0 2.0 67 KB

Django app to attach usable __repr__ and __str__ to any and all Django models, using unmigrated __unicode__ on Python 3

License: MIT License

Python 100.00%
python2 python3 dunder-methods monkey-patching django-models django-meta django-check django-admin django-testing

django-dunder's Introduction

django-dunder

django-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 for https://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.

Install

  1. pip install django-dunder
  2. Add django_dunder to INSTALLED_APPS before models that need dunders added.

To catch all models missing __str__ or __repr__, put it at the top of INSTALLED_APPS.

To quickly see how it improves the Django admin, install django-data-browser in development before and after, and click its "admin" column on any model that was using the Django default string representation.

Configure

To disable unicode warnings, set DUNDER_WARN_UNICODE = False.

For more control, in your settings, toggle these "auto", "force" and "exclude" settings.

To disable the automatic attaching for one or both of __str__ and __repr__, set one of

  • DUNDER_AUTO = False
  • DUNDER_AUTO_REPR = False
  • DUNDER_AUTO_STR = False
  • DUNDER_COPY_UNICODE = False

To force all models to use these methods, use DUNDER_FORCE = True, or set DUNDER_FORCE_REPR or DUNDER_FORCE_STR to True.

To force specific models only, DUNDER_FORCE_REPR and DUNDER_FORCE_STR may 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']

Note When the copying of __unicode__ is disabled on Python 3, and the Django setting DEBUG is also disabled, this app will raise ImproperlyConfigured if 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 set

  • DUNDER_REJECT_UNICODE = False

There is also a Django check for 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 to False.

  • DUNDER_CHECK_INACTIVE_UNICODE = 'warn'

Formatting

The 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 modifier ellipsis that 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 the forbiddenfruit library. For example, if datatype-tools is installed as directed, with imports in settings.py or 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 of datatype-tools, it provides a float.round() which uses two significant places by default while round(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 like havocesp/typext#1 arise.

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 fields

To show specific fields in either str() or repr(), two extra model meta options are automatically added by django-dunder:

from django.db import models

class MyModel(models.Model):
    uuid = models.TextField()
    first_name = models.TextField()
    last_name = models.TextField()
    ...

    Meta:
        str_fields = ('first_name', 'last_name')
        repr_fields = ('uuid', )

Explicit mixins

Alternatively disable auto mode (DUNDER_AUTO = False), and use the mixins, and set the :

from django_dunder.mixins import DunderModel

class MyModel(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 from INSTALLED_APPS.

To avoid that, use djsommo

Extending to other types

It 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 if its type dunders could be 'curse'd, especially if object.__str__ and object.__repr__ could be replaced.

Alternatives

django-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, several django.contrib models do not provide these dunder methods.

Inspiration was drawn from

They 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 in sentry.db.models into a base mixin model used throughout the project.

Starting a new project, and only interested in your own models? pydantic provides default and customisable dunders, and django-ninja provides a Django REST interface on top, and there are lots of other tools layered on top of pydantic, like pydantic-ui providing a Django Admin-like interface.

django-dunder's People

Stargazers

 avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

Forkers

rip9958

django-dunder's Issues

Python 2

There are a few minor bugs wrt Python 2, especially with unicode strings, and another just added in 0.3.0 when using the optional round() syntax.

Most importantly with Python 2 and unicode, there are not enough tests that pin-point the bugs, which helps identify how major or minor they are, and helps motivate doing the easy wins, leaving the bigger problems until there is external motivation, which may never eventuate given Python 2 status.

str: Use <Foo x> when x is sufficient

Following #8 , if there is only one important attribute, the format could change from

<Foo: x> to <Foo x> and even simply x if x is a sufficiently descriptive attribute

Add custom str() formats

The current format is User(...) .

The format closer to Django's default is <User: ...>.

The project should be able to define their own format string+formatters comprising at least variables model and attrs.

Perf testing

Need to do serious load testing to see how it performs , esp with formatting voodoo

str: Remove unnecessary foo=

There are many times when str() doesnt need to prefix attributes with foo= as the foo= is implied/understood by humans due to some other factor, such as the formatting of the attribute value, or the primacy of the attribute for that model.

Translation

Model name and instance value translations are (mostly) possible with __str__. It probably isnt wise, but it can help with third-party apps that have hard-coded strings, especially Enums.

Probably need to understand the context that __str__ is being invoked.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.