https://github.com/5monkeys/django-traits
https://github.com/5monkeys/django-traits
Last synced: about 1 year ago
JSON representation
- Host: GitHub
- URL: https://github.com/5monkeys/django-traits
- Owner: 5monkeys
- License: bsd-3-clause
- Created: 2021-10-06T10:54:32.000Z (over 4 years ago)
- Default Branch: main
- Last Pushed: 2021-10-12T13:12:28.000Z (over 4 years ago)
- Last Synced: 2025-03-06T10:02:19.781Z (over 1 year ago)
- Language: Python
- Homepage: https://pypi.org/project/django-traits/
- Size: 38.1 KB
- Stars: 2
- Watchers: 5
- Forks: 1
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README

django-traits
Define traits for Django models that works seamlessly both in-Python and using the ORM,
with coordinated tests.
### Installation
```bash
$ python3 -m pip install django-traits
```
### Example
```python
class Rich(Trait["Person"]):
q = models.Q(income__gt=1000)
def check_instance(self, instance: Person) -> bool:
return instance.income > 1000
class Person(models.Model):
is_rich = Rich()
income = models.PositiveIntegerField()
# Filter for rich people, this uses the ORM predicate as defined in q.
rich_people = Person.is_rich.all()
# Check if a person is rich, this uses the in-Python predicate as defined in check_instance().
person = Person.objects.first()
if person.is_rich:
print("Money is not a problem")
else:
print("This person is not rich")
```
The automated test factory makes it simple to write tests that guarantees that the
in-Python predicate stays in sync with its ORM counterpart. The following example
generates parameterized tests that checks boundary values.
```python
import pytest
from traits.tests import create_trait_test
parametrize_people = pytest.mark.parametrize(
"instance",
PersonFactory(),
PersonFactory(income=1000),
PersonFactory(income=1001),
)
class TestPerson:
test_is_rich = parametrize_people(create_trait_test(Person.is_rich))
```
The above example will generate three tests that checks that each given instance of
`Person` only appears in an ORM query result if the trait evaluates to `True` for that
instance, and that the result set is empty if it evaluates to `False`. So if the
implementations were to drift apart, for instance if the limit was increased to `2000`
in `check_instance()` but not in `q`, the tests would fail and enforce that the two
implementations are in sync.
You can also use [Hypothesis] to automatically generate test values.
```python
from traits.tests import create_trait_test
from hypothesis import given
from hypothesis.strategies import builds
from hypothesis.strategies import integers
people = builds(
PersonFactory.build,
income=integers(-9223372036854775808, 9223372036854775807),
)
class TestPerson:
test_is_rich = given(people)(create_trait_test(Person.is_rich))
```
[Hypothesis]: https://github.com/HypothesisWorks/hypothesis