Description
Code of Conduct
- I agree to follow Django's Code of Conduct
Feature Description
To save developer confusion, change the arguments for get_or_create
, like this:
def get_or_create(self, *, defaults=None, **kwargs)
Although this would technically create backward-compatibility issues, I would argue that, in practice, these would be very rare and easily fixed.
Alternatively, deprecate this function and create a new one, perhaps create_or_get
, that works this way.
Problem
When I unwittingly neglected to unpack a dict as arguments for get_or_create
, the result was a MultipleObjectsReturned
exception. While this was clearly a mistake (which I made at 1am today), the exception was misleading. It set me off on a wild goose chase, trying to work out how multiple objects matching the arguments could possibly exist.
The reason was that defaults
is a positional argument. This swallowed the dict I passed, and caused a zero-argument call to get
, which raised the exception.
The dict was actually locals()
, which I used to pass the arguments for a service module function to a one-liner get_or_create
—I just forgot to put **
in front of it. It's not the first time I've passed function arguments on that way (DRY and all that), and it's certainly not an unheard-of technique in Python.
OTOH, in a lot of Django code, and indeed the Django docs, I've only ever seen defaults
passed by keyword, after criteria arguments. And while a zero-argument get()
make sense for single-row tables, it's hard to imagine any developer positionally passing defaults to get_or_create
.
Request or proposal
proposal
Additional Details
While not strictly backwards compatible, I believe the developer confusion saved would greatly outweigh the minor and unlikely hassle that one or two devs may experience from this change. As I said, it's hard to imagine it actually breaking any existing code, and even if it did, it would cause an easy-to-fix NameError
or TypeError
: just type 'defaults=' . But it would likely save developers getting confused by MultipleObjectsReturned
for the same reason I was.
Implementation Suggestions
Just add the three characters to the function definition. Alternatively, deprecate get_or_create
, and create a different method, as in the feature description.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status