check if query exists using peewee
Asked Answered
C

3

15

I am using the Peewee library in Python and I want to check if a query exists. I do not want to create a record if it doesn't exist, so I don't want to use get_or_create. There must be a better solution than to use try/except with get but I don't see anything. Please let me know if there is a better way. Thanks.

Cholecyst answered 30/7, 2015 at 3:9 Comment(2)
Is there something wrong with try/except approach?Tani
Doesn't seem very elegant.Cholecyst
I
44

You can use .exists():

query = User.select().where(User.username == 'charlie')
if query.exists():
    # A user named "charlie" exists.
    cool()

http://docs.peewee-orm.com/en/latest/peewee/api.html?highlight=exists#SelectBase.exists

Informality answered 30/7, 2015 at 5:28 Comment(1)
If I am using db.atomic() to "get or create" multiple related entries as part of a single transaction (i.e. not using the function get_or_create() for each entry), which in your opinion is better to use - try/except, or exists()?Agraphia
B
18

If you just need to check existence use the accepted answer.

If you are going to use the record if it exists you can make use of Model.get_or_none() as this removes the need to use a try/catch and will not create a record if the record doesn't exist.

class User(peewee.Model):
    username = peewee.CharField(unique=True)

user = User.get_or_none(username='charlie')
if user is not None:
    # found user, do something with it
    pass
Bloodstream answered 28/5, 2019 at 13:29 Comment(1)
I was surprised by the downvotes, so I clarified my answer. My reading of the question suggested they wanted to do something with the object if it existed. Which was the question I had when I came across this question.Bloodstream
C
3

Alternatively, if you want to check if e.g. some other table refers this record, you can use WHERE EXISTS (subquery) clause. It is not supported natively by PeeWee, but it can be easily constructed:

subquery = Child.select(Param('1')).where(Child.parent == Parent.id)
parents_with_children = Parent.select().where(
    Clause(SQL('EXISTS'), subquery))

It is equivalent to the following SQL:

SELECT * FROM parent
WHERE EXISTS (SELECT 1 FROM child
              WHERE child.parent_id = parent.id);

Here I used SELECT 1 for subquery to avoid fetching unneeded information (like child.id). Not sure if such optimization is actually required.

UPD (Feb 2022)

After more than 5 years of peewee evolution, it looks like the Clause class is gone.

The following code may work (I didn't have a chance to test it though):

subquery = Child.select(Param('1')).where(Child.parent == Parent.id)
parents_with_children = Parent.select().where(
    NodeList((SQL('EXISTS'), subquery)))
Callao answered 13/4, 2016 at 14:44 Comment(3)
From where do you import Clause ? I cannot find it in the peewee source code.Brasilin
Notice this answer is more than 5 years old. Looks like Clause was removed or renamed since then. You may find this useful: github.com/coleifer/peewee/commit/2f0b3 - it is one of the latest commits mentioning Clause class as obsolete and proposing a replacement.Callao
I stumbled upon the following which seems to work: Parent.select().where(fn.EXISTS(subquery)). It seems that Peewee is smart enough that you don't even need the Param('1') in your subquery. So subquery = Child.select().where(Child.parent == Parent.id) actually turns into a select 1 when used in the exists for some reason.Brasilin

© 2022 - 2024 — McMap. All rights reserved.