Make `get_or_create`'s arguments keyword-only
- Dominant language
- No language data
- Stars
- 188
- Forks
- 7
- PR merge metrics
- No merged PRs in 30d
Description
### Code of Conduct
- [x] I agree to follow Django's Code of Conduct
### Feature Description
To save developer confusion, change the arguments for `get_or_create`, like this:
```python
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.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.