Opened 8 years ago

Closed 8 years ago

#26638 closed New feature (fixed)

Allow callable in defaults argument for QuerySet.get_or_create

Reported by: Maxime Lorant Owned by: Will Koster
Component: Database layer (models, ORM) Version: dev
Severity: Normal Keywords:
Cc: Will Koster Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: yes
Easy pickings: yes UI/UX: no

Description (last modified by Maxime Lorant)

It would be nice if get_or_create handles callable in the defaults parameter so the defaults value are not computed at each selection. Indeed, if your default values for insertion contains selection of related object or any long computation, it is done at each call, even if the object can be retrieved without insertion (and so the defaults parameter is not used).

In term of code, I would like to do something like this:

SomeObject.objects.get_or_create(
       key1=value1, 
       key2=value2,
       defaults={
             'key3': lambda: long_processing_to_get_default(),
             # or even
             'key3': lambda: OtherModel.objects.get(pk=request.some_value)
       }
)

For backward-compatibility and ease of writing, it should still accept values that are not callables. See the patch attached (unit tests are missing so it is not complete!) My patch is wrong in fact: it computes the value before the selection and it consider the dict as a whole callable instead of a single key of the dict... Anyway the implementation inside the except DoesNotExist should be easy :)

Attachments (1)

patch26638.txt (953 bytes ) - added by Maxime Lorant 8 years ago.

Download all attachments as: .zip

Change History (10)

by Maxime Lorant, 8 years ago

Attachment: patch26638.txt added

comment:1 by Maxime Lorant, 8 years ago

Description: modified (diff)

comment:2 by Maxime Lorant, 8 years ago

Description: modified (diff)

comment:3 by Will Koster, 8 years ago

I sent a pull request that solves this (https://github.com/django/django/pull/6650). My understanding of the ticket is that it should evaluate the callable if and only if the object needs to be created, and that's what the code does. Is that right?

Also, it passes all the tests under SQLite.

comment:4 by Will Koster, 8 years ago

Has patch: set
Needs tests: set
Owner: changed from nobody to Will Koster
Status: newassigned

comment:5 by Will Koster, 8 years ago

Needs tests: unset

comment:6 by Tim Graham, 8 years ago

Needs documentation: set
Triage Stage: UnreviewedAccepted

comment:7 by Will Koster, 8 years ago

Cc: Will Koster added

comment:8 by Tim Graham, 8 years ago

Needs documentation: unset
Patch needs improvement: set

Left comments for improvement on the PR. Please uncheck "Patch needs improvement" after updating.

comment:9 by Tim Graham <timograham@…>, 8 years ago

Resolution: fixed
Status: assignedclosed

In 9899347:

Fixed #26638 -- Allowed callable arguments for QuerySet.get_or_create()/update_or_create() defaults.

Note: See TracTickets for help on using tickets.
Back to Top