Secrets¶
Was there a time where you wished you could have a way of querying the database and not returning some sentive data without the hassle of filtering all over the codebase? Well, say no more.
The secret
is a special attribute of the fields that is available on each field
that basically if set to True
and using the exclude_secrets
will make sure it will never
return any sensitive data.
In other words, it will safely expose your data.
Exclude Secrets¶
How does this work in reality? Well, very simple actually. You will need to set the secret
attribute to True
and when you want to safely expose the data via query, call the exclude_secrets
.
No worries, the secret
attribute is not stored in the database in any way.
Let us see an example.
import saffier
from saffier import Database, Registry
database = Database("sqlite:///db.sqlite")
models = Registry(database=database)
class User(saffier.Model):
name = saffier.CharField(max_length=50)
email = saffier.EmailField(max_lengh=100)
password = saffier.CharField(max_length=1000, secret=True)
class Meta:
registry = models
Check the password
field. That same field has the secret
set to True
and this is great because
now we want to query the database and get some records without worrying about leaking the password
to the outside world.
For this we will be using a special method called exclude_secrets
. This function also returns a
queryset which means you can mix with any other operation as per normal
usage but with the plus of not exposing the secrets.
exclude_secrets¶
This is the special function that allows all the magic to happen. Let us see how it would look like if we were using it.
The syntax is very simple.
Model.query.exclude_secrets()
Example¶
Let us create some data.
await User.query.create(name="Saffier", email="saffier@example.dev", password="A@Pass123")
await User.query.create(name="Esmerald", email="esmerald@esmerald.dev", password="A@Pass321")
Now, let us query excluding the secrets.
await User.query.exclude_secrets()
This will return all the users as per normal query but let us see more in detail.
user = await User.query.exclude_secrets(id=1)
This will return the user with id=1
which is the name Saffier
. Now, let us see how it would look
like seeing all the details of the object.
user.model_dump()
{"id": 1, "name": "Saffier", "email": "saffier@example.com"}
As you can see, there is no password
being displayed at all and that is because the field has
the secret
declared. This can be specially useful if you don't want to be bother to filter and
manipulate all of those details manually and simlpy still using the normal ORM queries without any
hassle.
Other examples¶
As mentioned before, you can mix the operations with the exclude_secrets
which means you can do
things like this.
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 the list goes on and on.
Make the field available¶
What if you want to expose the fields that previously had the secret
declared?
There are different ways of making this happen.
One of the ways is by not using the exclude_secrets queryset and the other is by removing the
flag secret
from the field.
Removing the flag has no issue since you can add it back at any given time but the best way it would
be by simply not calling exclude_secrets
at all since the flag secret=True
is only used for that
given queryset which also means it won't impact anything in your models.