piccolo-orm / piccolo

A fast, user friendly ORM and query builder which supports asyncio.
https://piccolo-orm.com/
MIT License
1.45k stars 91 forks source link

make Readable for boolean fields more user-friendly #741

Open trondhindenes opened 1 year ago

trondhindenes commented 1 year ago

As far as I can see, if using Readable and get_readable, boolean fields are represented as f and t (False and True). It would be good if it was possible to represent these in a more user-friendly way - Maybe even make the default similar to Python's string representation of booleans:

In [1]: str(True)
Out[1]: 'True'

In [2]: str(False)
Out[2]: 'False'
sinisaos commented 1 year ago

@trondhindenes For boolean readable fields, Piccolo returns the database representation of the boolean column (Sqlite "0" or "1" using PRINTF, Postgres "f" or "t" using FORMAT). I think the easiest way to get a nicer display is to use Python and modify the results something like this

result = await Band.select(Band.get_readable())
for item in result:
    if item["readable"] in ["0", "f"]:
        item["readable"] = "False"
    else:
        item["readable"] = "True"
print(result)

and result is

[
   {
      "readable":"False"
   },
   {
      "readable":"True"
   }
]

I hope that's ok for you.

trondhindenes commented 1 year ago

Hi thanks - I assumed that was the case.

I'm using readables with class methods to make piccolo-admin print nicer strings:

    @classmethod
    def get_readable(cls) -> Readable:
        return Readable(template="%s (expired: %s)", columns=[cls.name, cls.expired])

I just assumed there wasn't much I could do in there, but now that I actually read the code I can ofc manipulate the Readable before it's returned. I should have double-checked before opening the issue. Thanks!

dantownsend commented 1 year ago

Hi - sorry for the slow reply, I managed to catch the flu over the holidays.

PR https://github.com/piccolo-orm/piccolo/pull/742 offers another solution:

class DiscountCode(Table):
    code = UUID()
    active = Boolean(default=True, null=True)

    @classmethod
    def get_readable(cls) -> Readable:
        return Readable(
            template="%s - %s",
            columns=[
                cls.code,
                SelectRaw(
                    "CASE WHEN active THEN 'active' ELSE 'inactive' END"
                ),
            ],
        )

We added SelectRaw recently, so the PR makes it so you can use it with Readable.

What do you both think?

sinisaos commented 1 year ago

@dantownsend This looks and works great and is nicer than manipulating the result.

trondhindenes commented 1 year ago

Nice! This more than covers my use case. I'd love to see "advanced usage" snippets like this in the docs as well