Opened 8 years ago

Closed 8 years ago

#27070 closed New feature (invalid)

Support for `Q` objects in `get_or_create` and `update_or_create`

Reported by: Flavio Curella Owned by: nobody
Component: Database layer (models, ORM) Version: dev
Severity: Normal Keywords:
Cc: Triage Stage: Someday/Maybe
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Since Q objects can be used to .filter queryset,I think it would make sense to leverage their functionality when looking up for objects in get_or_create or update_or_create.

There currently isn't any way to use Q objects when checking for existence in get_or_create and update_or_create. There are two main reasons for that:

  1. The signature of these methods prevents the usage of unnamed arguments
  2. When ORing Q objects, if the lookup fails, and those fields are not specified in defaults, we have undefined values for the object that we need to create.

We could address 1. by adding a keyword argument (let's call it query for now), so that the signature would be get_or_create(defaults=None, query=None, **kwargs). It could then be used in this way:

obj, created = Person.objects.get_or_create(
    query=Q(first_name="George") | Q(first_name='Bruce'),
    defaults={"last_name": "Harrison"},
)

Re 2., we have two options:

2a. Leave the ambiguous fields undefined (but this would be inconsistent with the 'non-query' behavior).
2b. Force the user to specify the field in defaults by raising some exception. Not happy about duplicating data in query and in defaults

Change History (7)

comment:2 by Tim Graham, 8 years ago

Triage Stage: UnreviewedSomeday/Maybe

I'm not immediately convinced the additional complexity is a good idea. Don't forget that adding a new keyword argument to get_or_create() could be backwards-incompatible for any models that have that field name. Could you write to the DevelopersMailingList to get some feedback?

comment:3 by Jeff Nuss, 8 years ago

One thing I like about this proposal is that it makes the functionality of get_or_create() and update_or_create() feel more consistent with other query methods that can use Q objects like get(), filter() etc. We would probably want to use a similar argument like defaults__exact for the case of a model having query as a field name.

comment:5 by Simon Charette, 8 years ago

There currently isn't any way to use Q objects when checking for existence in get_or_create and update_or_create.

Isn't filter(Q(first_name='Bryan') | Q(first_name='Bruce')).get_or_create({'last_name': 'Harrison'}) working?

comment:6 by Flavio Curella, 8 years ago

Replying to charettes:

There currently isn't any way to use Q objects when checking for existence in get_or_create and update_or_create.

Isn't filter(Q(first_name='Bryan') | Q(first_name='Bruce')).get_or_create({'last_name': 'Harrison'}) working?

O_O It didn't occur to me that it could be done that way. Seems to work exactly as I'd expect.

Should I update my PR to simply add some tests of combining .filter with .get_or_create and maybe show an example in the docs?

Last edited 8 years ago by Flavio Curella (previous) (diff)

comment:7 by Flavio Curella, 8 years ago

Resolution: invalid
Status: newclosed

On a second thought, I dont think more work on the docs is necessary. Closing as 'invalid'

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