Skip to content

Secrets

Have you ever wished for a way to query the database and omit sensitive data without the hassle of filtering throughout your codebase? Your wish is granted.

The secret attribute is a special feature of fields, available on each field. When set to True, and used in conjunction with exclude_secrets, it ensures that sensitive data is never returned.

In essence, it provides a safe way to expose your data.

Exclude Secrets

How does this work in practice? It's quite simple. Set the secret attribute to True, and when you want to safely expose data via a query, call exclude_secrets.

Rest assured, the secret attribute is not stored in the database in any way.

Let's look at an example.

import edgy
from edgy import Database, Registry

database = Database("sqlite:///db.sqlite")
models = Registry(database=database)


class User(edgy.Model):
    name: str = edgy.CharField(max_length=50)
    email: str = edgy.EmailField(max_lengh=100)
    password: str = edgy.CharField(max_length=1000, secret=True)

    class Meta:
        registry = models

Notice the password field. It has the secret attribute set to True. This is beneficial because now we can query the database and retrieve records without worrying about leaking the password to the outside world.

We'll use a special method called exclude_secrets. This function returns a queryset, allowing you to combine it with other operations as usual, but with the added benefit of not exposing secrets.

exclude_secrets

This is the function that makes all the magic happen. Let's see how it's used.

The syntax is straightforward.

Model.query.exclude_secrets()

Example

Let's create some data.

await User.query.create(name="Edgy", email="edgy@example.dev", password="A@Pass123")
await User.query.create(name="Esmerald", email="esmerald@esmerald.dev", password="A@Pass321")

Now, let's query, excluding the secrets.

await User.query.exclude_secrets()

This will return all users as a normal query would. Let's look at it more closely.

user = await User.query.exclude_secrets(id=1)

This will return the user with id=1, which is named "Edgy". Now, let's see the full object details.

user.model_dump()

{"id": 1, "name": "Edgy", "email": "edgy@example.com"}

As you can see, the password is not displayed at all. This is because the field has the secret attribute declared. This is especially useful when you don't want to manually filter and manipulate these details, and prefer to use standard ORM queries without any hassle.

Other Examples

As mentioned, you can combine operations with exclude_secrets.

users = await User.query.filter(id=1).exclude_secrets()
users = await User.query.filter(id=1).exclude_secrets().get() # returns only 1 object
users = await User.query.exclude_secrets().only("email")

And so on.

Make the Field Available

What if you want to expose fields that previously had the secret attribute declared?

There are a few ways to do this.

One way is by not using the exclude_secrets queryset. Another is by removing the secret flag from the field.

Removing the flag is fine, as you can add it back at any time. However, the best approach is to simply not call exclude_secrets at all. The secret=True flag is only used for that specific queryset, meaning it won't affect anything in your models.