pony icon indicating copy to clipboard operation
pony copied to clipboard

get_or_create method for entities

Open blueyed opened this issue 9 years ago • 10 comments

A method like get_or_create would be useful to avoid boilerplate code with the following pattern:

@classmethod
def get_or_create(cls, **kwargs):
    r = cls.get(**kwargs)
    if r is None:
        return cls(**kwargs), True
    else:
        return r, False

See also Django's get_or_create.

I've just started looking at Pony ORM, and therefore might have likely missed something.

blueyed avatar Jul 01 '15 14:07 blueyed

I vote for similar method

@classmethod
def update_or_create(cls, **kwargs):
    try:
        instance = cls[tuple(
            kwargs[pk_attr.name]
            for pk_attr in cls._pk_attrs_
        )]
    except orm.ObjectNotFound:
        return cls(**kwargs)
    else:
        instance.set(**kwargs)

        return instance

timka-s avatar Jul 30 '15 15:07 timka-s

+1

tonycpsu avatar Feb 14 '16 03:02 tonycpsu

I use this trick:

from pony.orm.core import EntityMeta
from pony import orm

def upsert(cls, get, set=None):
    """
    Interacting with Pony entities.

    :param cls: The actual entity class
    :param get: Identify the object (e.g. row) with this dictionary
    :param set: 
    :return:
    """
    # does the object exist
    assert isinstance(cls, EntityMeta), "{cls} is not a database entity".format(cls=cls)

    # if no set dictionary has been specified
    set = set or {}

    if not cls.exists(**get):
        # make new object
        return cls(**set, **get)
    else:
        # get the existing object
        obj = cls.get(**get)
        for key, value in set.items():
            obj.__setattr__(key, value)
        return obj

tschm avatar Nov 13 '17 10:11 tschm

Relatedly, having an Entity method like update would be nice, which would be equivalent to:

def update(**values):
    for key, value in values.items():
        self.__setattr__(key, value)

fluffy-critter avatar Sep 19 '18 06:09 fluffy-critter

There is such method called set.

Vitalium avatar Sep 19 '18 07:09 Vitalium

Oh, so there is! Thanks.

Looks like @tschm's upsert method can be simplified, in that case.

fluffy-critter avatar Sep 19 '18 08:09 fluffy-critter

Has this been implemented yet? This seems like something that would come out of the box

cercos avatar Sep 01 '19 23:09 cercos

Really need this one

zhaobenx avatar Jul 07 '20 00:07 zhaobenx

It would be awesome to have this.

asophila avatar Nov 10 '20 14:11 asophila

I vote for similar method

@classmethod
def update_or_create(cls, **kwargs):
    try:
        instance = cls[tuple(
            kwargs[pk_attr.name]
            for pk_attr in cls._pk_attrs_
        )]
    except orm.ObjectNotFound:
        return cls(**kwargs)
    else:
        instance.set(**kwargs)

        return instance

This function is perfect! should just be added to pony!

EDIT: I take that back, we should probably create, and catch an IntegrityError, and then update instead to avoid a race condition.

pykler avatar Jan 27 '22 16:01 pykler