Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python peewee save() doesn't work as expected

I'm inserting/updating objects into a MySQL database using the peewee ORM for Python. I have a model like this:

class Person(Model):
    person_id = CharField(primary_key=True)
    name = CharField()

I create the objects/rows with a loop, and each time through the loop have a dictionary like:

pd = {"name":"Alice","person_id":"A123456"}

Then I try creating an object and saving it.

po = Person()
for key,value in pd.items():
    setattr(po,key,value)
po.save()

This takes a while to execute, and runs without errors, but it doesn't save anything to the database -- no records are created.

This works:

Person.create(**pd)

But also throws an error (and terminates the script) when the primary key already exists. From reading the manual, I thought save() was the function I needed -- that peewee would perform the update or insert as required.

Not sure what I need to do here -- try getting each record first? Catch errors and try updating a record if it can't be created? I'm new to peewee, and would normally just write INSERT ... ON DUPLICATE KEY UPDATE or even REPLACE.

like image 652
Martin Burch Avatar asked May 04 '15 19:05

Martin Burch


2 Answers

Person.save(force_insert=True)

It's documented: http://docs.peewee-orm.com/en/latest/peewee/models.html#non-integer-primary-keys-composite-keys-and-other-tricks

like image 69
coleifer Avatar answered Sep 18 '22 22:09

coleifer


I've had a chance to re-test my answer, and I think it should be replaced. Here's the pattern I can now recommend; first, use get_or_create() on the model, which will create the database row if it doesn't exist. Then, if it is not created (object is retrieved from db instead), set all the attributes from the data dictionary and save the object.

po, created = Person.get_or_create(person_id=pd["person_id"],defaults=pd)
if created is False:
    for key in pd:
        setattr(fa,key,pd[key])
    po.save()

As before, I should mention that these are two distinct transactions, so this should not be used with multi-user databases requiring a true upsert in one transaction.

like image 31
Martin Burch Avatar answered Sep 20 '22 22:09

Martin Burch