Opened 7 years ago

Closed 7 years ago

Last modified 6 years ago

#10148 closed (invalid)

get_or_create function documentation is not clear enough

Reported by: batiste Owned by: nobody
Component: Documentation Version: 1.0
Severity: Keywords: get_or_create, documentation
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: UI/UX:

Description

get_or_create function documentation doesn't tell that defauts dictionary argument won't override the attributes when an object already exist in the database:

import datetime
from result.models import Game
d = datetime.datetime(2009, 4, 18, 16, 1)  
g, c = Game.objects.get_or_create(id=116)
g.start_date
>>> datetime.datetime(2009, 4, 18, 16, 0)
g, c = Game.objects.get_or_create(id=116, defaults={"start_date":d})
g.start_date
>>> datetime.datetime(2009, 4, 18, 16, 0)

This comportement is not clear in the documentation and should be specified. Something like this is needed to be sure that the attributes are updated:

for k, v in game_attrs_update.items():
    setattr(g, k, v)

Change History (4)

comment:1 Changed 7 years ago by batiste

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset

Sorry I just inversed the whole thing:

>>> import datetime
>>> from result.models import Game
>>> d = datetime.datetime(2009, 4, 18, 16, 1)
datetime.datetime(2009, 4, 18, 16, 1)  
>>> g, c = Game.objects.get_or_create(id=116)
>>> g.start_date
datetime.datetime(2009, 4, 18, 16, 0)
>>> g, c = Game.objects.get_or_create(id=116, defaults={"start_date":d})
>>> g.start_date
datetime.datetime(2009, 4, 18, 16, 0)

comment:2 Changed 7 years ago by batiste

I figured out that the better way to achieve what I want is to do that:

g, c = Game.objects.get_or_create(id=116, **defaults)

comment:3 Changed 7 years ago by arien

  • Resolution set to invalid
  • Status changed from new to closed

The documentation on get_or_create says:

    Any keyword arguments passed to ``get_or_create()`` -- *except* an optional one
    called ``defaults`` -- will be used in a ``get()`` call. If an object is found,
    ``get_or_create()`` returns a tuple of that object and ``False``. If an object
    is *not* found, ``get_or_create()`` will instantiate and save a new object,
    returning a tuple of the new object and ``True``.

(It also shows an example of using get_or_create in terms of get and create.)

So, in your example, get_or_create looks for a Game object with id=116, one is found and returned "as-is".

By the way, the "better way" you mention:

g, c = Game.objects.get_or_create(id=116, **defaults)

will look up a Game object with id=116 and start_date=datetime.datetime(2009, 4, 18, 16, 1). This object isn't found, so one will be created. The result is an IntegrityError, since you're trying to use the same primary key for more than one object.

Closing as invalid since this seems to be clearly documented in both English and Python.

comment:4 Changed 6 years ago by arien

batiste, you might want to track #3182, which proposes adding an update_or_create to QuerySet objects.

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