Opened 2 years ago

Closed 22 months ago

#34280 closed New feature (fixed)

Support create defaults for update_or_create

Reported by: Timothy Schilling Owned by: Timothy Schilling
Component: Database layer (models, ORM) Version: dev
Severity: Normal Keywords:
Cc: Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

I proposed the idea of extending update_or_create to support specifying a different set of defaults for the create operation on the [forum](https://forum.djangoproject.com/t/feature-idea-update-or-create-to-allow-different-defaults-for-create-and-update-operations/18300/15). There seems to be consensus it's a positive add to Django.

Adam raised concerns with my proposed approach of adding a create_defaults parameter to the function since this would conflict with any fields on a model named, create_defaults. Jeff did a code search on github for that term and didn't find any matches. I suspect if someone where using a field named create_defaults, it would be a JSON or object type field. Those don't seem like reasonable candidates to be part of a UniqueConstraint, which should be underlying the look-up arguments to update_or_create.

I do like the idea of having a separate parameter for create_defaults, but if we must preserve 100% backwards compatibility, Adam's suggestion of having defaults be set to another object makes the most sense.

My blocking question is, which approach should I take?

From the forum post:

I’ve run into a use-case in which it’d be helpful to have the ability to specify a different set of defaults for the update operation compared to the create operation. While I don’t expect my particular use case to translate, here’s a more generic one.
Given the following Record model:

class Record(models.Model):
    some_id = models.CharField(unique=True)
    created_by = models.ForeignKey(User, ...)
    modified_by = models.ForeignKey(User, null=True, blank=True, ...)

When a record is created, we would want to set created_by, but if it’s being updated, we’d want to set modified_by. This use case can’t be solved by using update_or_create, unless it allows for us to specify a different set of default values.

Record.objects.update_or_create(
    some_id=some_value,
    defaults={"modified_by": user},
    create_defaults={"created_by": user},
)

Change History (7)

comment:1 by Timothy Schilling, 2 years ago

Owner: changed from nobody to Timothy Schilling

comment:2 by Mariusz Felisiak, 2 years ago

Triage Stage: UnreviewedAccepted

comment:3 by Timothy Schilling, 23 months ago

Has patch: set

Here's a PR with the first version of the changes. https://github.com/django/django/pull/16511

comment:4 by Mariusz Felisiak, 23 months ago

Needs documentation: set

comment:5 by Timothy Schilling, 23 months ago

I ended up going with the create_defaults approach since we have a workaround for the lookup via create_defaults__exact.

comment:6 by Mariusz Felisiak, 22 months ago

Needs documentation: unset
Triage Stage: AcceptedReady for checkin

comment:7 by Mariusz Felisiak <felisiak.mariusz@…>, 22 months ago

Resolution: fixed
Status: assignedclosed

In c580847:

Fixed #34280 -- Allowed specifying different field values for create operation in QuerySet.update_or_create().

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