Issue: BooleanField is_true and is_false methods
Author: danilobellini
State: closed
Created: 2016-10-26 14:42:04

# Proposal

Add methods to BooleanField so that we can create expressions like `MyModel.my_field.is_true()` and `MyModel.my_field.is_false()` instead of `MyModel.my_field == True` and `MyModel.my_field == False`.
# Rationale

I'm using `flake8`, with a selected list of [pycodestyle error codes](http://pycodestyle.readthedocs.io/en/latest/intro.html#error-codes), and using `MyModel.my_field == True` triggers the E712 error, _comparison to True should be 'if cond is True:' or 'if cond:'_.

That would be consistent with the `is_null` method, which is used instead of a "MyModel.my_field == None".
# Reference implementation

```
peewee.BooleanField.is_true = lambda self: peewee.Expression(self, peewee.OP.EQ, True)
peewee.BooleanField.is_false = lambda self: peewee.Expression(self, peewee.OP.EQ, False)
```


I appreciate you taking the time to submit this issue.  Unfortunately, peewee does quite a few things that many linters find egregious. I don't use linters myself, so it doesn't bother me and personally I'm not interested in adding code simply to satisfy flake8. Thanks for providing a reference implementation, anyone who is interested can use your code or subclass `BooleanField` and add the suggested methods.


I'm also not concerned with the peewee code style, I'm concerned that peewee is clearly forcing its users to take a move against PEP8 when using boolean fields, besides the consistency with `is_null`. I mean, what I propose is about the API, not about the peewee code itself.


Peewee isn't forcing anyone to do anything.


It's not forcing people to become peewee users, but it's forcing its users to follow its API.

The `== True` is spread in the documentation examples. Is there any example with some different approach to avoid `Something.my_field == True` while doing the same? I might be missing something.


> Is there any example with some different approach to avoid `Something.my_field == True` while doing the same?

You've shared a nice one.


A lot of things have changed since this discussion, and I think the original "gripe" has been fixed. But I wanted to confirm...

The main point is that you no longer need to use the `== True/False` syntax, though there are certain cases where it could be necessary (mainly when dealing with NULL values)


```SQL
    q1 = Event.select(Event.id).where(Event.is_published)
    print(q1)
    >> SELECT `t1`.`id` FROM `event` AS `t1` WHERE `t1`.`is_published`

    q1 = Event.select(Event.id).where(~Event.is_published)
    print(q1)
    >> SELECT `t1`.`id` FROM `event` AS `t1` WHERE NOT `t1`.`is_published`

    q1 = Event.select(Event.id).where(Event.is_published == True)
    print(q1)
    >> SELECT `t1`.`id` FROM `event` AS `t1` WHERE (`t1`.`is_published` = 1)

    q1 = Event.select(Event.id).where(Event.is_published == False)
    print(q1)
    >> SELECT `t1`.`id` FROM `event` AS `t1` WHERE (`t1`.`is_published` = 0)
```

Usually both versions will be equivalent. But if the boolean field supports NULL, then you need to be careful which version you use.

The same things goes for hybrid attributes. The reason I arrived at this ticket was because I noticed a query was not using an index that it should have been. It was using the `== False` syntax on a hybrid attribute/expression, which resulted in the query being something like `WHERE (( complex expression ) == 0)`, but when using the negation operator `~`, the SQL is `WHERE NOT ( complex expression)` and the index was used correctly. 


The documentation seems to mainly still use the `== True/False` variation. Maybe I missed it, but it could be good to add some details on the difference between these two variations of boolean expressions.