Skip to content

Commit 77d1664

Browse files
committed
docs: Update docs using condition parameter
1 parent 64648ef commit 77d1664

File tree

4 files changed

+80
-62
lines changed

4 files changed

+80
-62
lines changed

README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,17 @@ class Article(LifecycleModel):
2424
status = models.ChoiceField(choices=['draft', 'published'])
2525
editor = models.ForeignKey(AuthUser)
2626

27-
@hook(BEFORE_UPDATE, when='contents', has_changed=True)
27+
@hook(BEFORE_UPDATE, WhenFieldHasChanged("contents", has_changed=True))
2828
def on_content_change(self):
2929
self.updated_at = timezone.now()
3030

31-
@hook(AFTER_UPDATE, when="status", was="draft", is_now="published")
31+
@hook(
32+
AFTER_UPDATE,
33+
condition=(
34+
WhenFieldValueWas("status", value="draft")
35+
& WhenFieldValueIs("status", value="published")
36+
)
37+
)
3238
def on_publish(self):
3339
send_email(self.editor.email, "An article has published!")
3440
```

docs/examples.md

Lines changed: 60 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ Or you want to email a user when their account is deleted. You could add the dec
3131
Or if you want to enqueue a background job that depends on state being committed to your database
3232

3333
```python
34-
@hook(AFTER_CREATE, on_commit=True)
35-
def do_after_create_jobs(self):
36-
enqueue_job(send_item_shipped_notication, self.item_id)
34+
@hook(AFTER_CREATE, on_commit=True)
35+
def do_after_create_jobs(self):
36+
enqueue_job(send_item_shipped_notication, self.item_id)
3737
```
3838

3939
Read on to see how to only fire the hooked method if certain conditions about the model's current and previous state are met.
@@ -43,56 +43,66 @@ Read on to see how to only fire the hooked method if certain conditions about th
4343
Maybe you only want the hooked method to run under certain circumstances related to the state of your model. If a model's `status` field change from `"active"` to `"banned"`, you may want to send an email to the user:
4444

4545
```python
46-
@hook(AFTER_UPDATE, when='status', was='active', is_now='banned')
47-
def email_banned_user(self):
48-
mail.send_mail(
49-
'You have been banned', 'You may or may not deserve it.',
50-
'communitystandards@corporate.com', ['mr.troll@hotmail.com'],
51-
)
46+
@hook(
47+
AFTER_UPDATE,
48+
condition=(
49+
WhenFieldValueWas("status", value="active")
50+
& WhenFieldValueIs('status', value='banned')
51+
)
52+
)
53+
def email_banned_user(self):
54+
mail.send_mail(
55+
'You have been banned', 'You may or may not deserve it.',
56+
'communitystandards@corporate.com', ['mr.troll@hotmail.com'],
57+
)
5258
```
5359

54-
The `was` and `is_now` keyword arguments allow you to compare the model's state from when it was first instantiated to the current moment. You can also pass `"*"` to indicate any value - these are the defaults, meaning that by default the hooked method will fire. The `when` keyword specifies which field to check against.
60+
The `WhenFieldValueWas` and `WhenFieldValueIs` conditions allow you to compare the model's state from when it was first instantiated to the current moment. You can also pass `"*"` to indicate any value - these are the defaults, meaning that by default the hooked method will fire.
5561

5662
## Preventing state transitions
5763

5864
You can also enforce certain disallowed transitions. For example, maybe you don't want your staff to be able to delete an active trial because they should expire instead:
5965

6066
```python
61-
@hook(BEFORE_DELETE, when='has_trial', is_now=True)
62-
def ensure_trial_not_active(self):
63-
raise CannotDeleteActiveTrial('Cannot delete trial user!')
67+
@hook(BEFORE_DELETE, condition=WhenFieldValueIs("has_trial", value=True))
68+
def ensure_trial_not_active(self):
69+
raise CannotDeleteActiveTrial('Cannot delete trial user!')
6470
```
6571

66-
We've omitted the `was` keyword meaning that the initial state of the `has_trial` field can be any value ("*").
67-
6872
## Any change to a field
6973

70-
You can pass the keyword argument `has_changed=True` to run the hooked method if a field has changed.
74+
You can use the `WhenFieldValueChangesTo` condition to run the hooked method if a field has changed.
7175

7276
```python
73-
@hook(BEFORE_UPDATE, when='address', has_changed=True)
74-
def timestamp_address_change(self):
75-
self.address_updated_at = timezone.now()
77+
@hook(BEFORE_UPDATE, condition=WhenFieldHasChanged("address", has_changed=True))
78+
def timestamp_address_change(self):
79+
self.address_updated_at = timezone.now()
7680
```
7781

7882
## When a field's value is NOT
7983

8084
You can have a hooked method fire when a field's value IS NOT equal to a certain value.
8185

8286
```python
83-
@hook(BEFORE_SAVE, when='email', is_not=None)
84-
def lowercase_email(self):
85-
self.email = self.email.lower()
87+
@hook(BEFORE_SAVE, condition=WhenFieldValueIsNot("email", value=None))
88+
def lowercase_email(self):
89+
self.email = self.email.lower()
8690
```
8791

8892
## When a field's value was NOT
8993

9094
You can have a hooked method fire when a field's initial value was not equal to a specific value.
9195

9296
```python
93-
@hook(BEFORE_SAVE, when='status', was_not="rejected", is_now="published")
94-
def send_publish_alerts(self):
95-
send_mass_email()
97+
@hook(
98+
BEFORE_SAVE,
99+
condition=(
100+
WhenFieldValueWasNot("status", value="rejected")
101+
& WhenFieldValueIs("status", value="published")
102+
)
103+
)
104+
def send_publish_alerts(self):
105+
send_mass_email()
96106
```
97107

98108
## When a field's value changes to
@@ -101,53 +111,49 @@ You can have a hooked method fire when a field's initial value was not equal to
101111
but now is.
102112

103113
```python
104-
@hook(BEFORE_SAVE, when='status', changes_to="published")
114+
@hook(BEFORE_SAVE, condition=WhenFieldValueChangesTo("status", value="published"))
105115
def send_publish_alerts(self):
106116
send_mass_email()
107117
```
108118

109-
Generally, `changes_to` is a shorthand for the situation when `was_not` and `is_now` have the
110-
same value. The sample above is equal to:
119+
Generally, `WhenFieldValueChangesTo` is a shorthand for the situation when `WhenFieldValueWasNot` and `WhenFieldValueIs`
120+
conditions have the same value. The sample above is equal to:
111121

112122
```python
113-
@hook(BEFORE_SAVE, when='status', was_not="published", is_now="published")
114-
def send_publish_alerts(self):
115-
send_mass_email()
123+
@hook(
124+
BEFORE_SAVE,
125+
condition=(
126+
WhenFieldValueWasNot("status", value="published")
127+
& WhenFieldValueIs("status", value="published")
128+
)
129+
)
130+
def send_publish_alerts(self):
131+
send_mass_email()
116132
```
117133

118134
## Stacking decorators
119135

120136
You can decorate the same method multiple times if you want to hook a method to multiple moments.
121137

122138
```python
123-
@hook(AFTER_UPDATE, when="published", has_changed=True)
124-
@hook(AFTER_CREATE, when="type", has_changed=True)
125-
def handle_update(self):
126-
# do something
127-
```
128-
129-
## Watching multiple fields
130-
131-
If you want to hook into the same moment, but base its conditions on multiple fields, you can use the `when_any` parameter.
132-
133-
```python
134-
@hook(BEFORE_SAVE, when_any=['status', 'type'], has_changed=True)
135-
def do_something(self):
136-
# do something
139+
@hook(AFTER_UPDATE, condition=WhenFieldHasChanged("published", has_changed=True))
140+
@hook(AFTER_CREATE, condition=WhenFieldHasChanged("type", has_changed=True))
141+
def handle_update(self):
142+
# do something
137143
```
138144

139145
## Going deeper with utility methods
140146

141-
If you need to hook into events with more complex conditions, you can take advantage of `has_changed` and `initial_value` [utility methods](advanced.md):
147+
If you need to hook into events with more complex conditions, you can [write your own conditions](advanced.md), or take advantage of `has_changed` and `initial_value` [utility methods](advanced.md):
142148

143149
```python
144-
@hook(AFTER_UPDATE)
145-
def on_update(self):
146-
if self.has_changed('username') and not self.has_changed('password'):
147-
# do the thing here
148-
if self.initial_value('login_attempts') == 2:
149-
do_thing()
150-
else:
151-
do_other_thing()
150+
@hook(AFTER_UPDATE)
151+
def on_update(self):
152+
if self.has_changed('username') and not self.has_changed('password'):
153+
# do the thing here
154+
if self.initial_value('login_attempts') == 2:
155+
do_thing()
156+
else:
157+
do_other_thing()
152158
```
153159

docs/fk_changes.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class UserAccount(LifecycleModel):
1414
email = models.CharField(max_length=600)
1515
employer = models.ForeignKey(Organization, on_delete=models.SET_NULL)
1616

17-
@hook(AFTER_UPDATE, when="employer", has_changed=True)
17+
@hook(AFTER_UPDATE, condition=WhenFieldHasChanged("employer", has_changed=True))
1818
def notify_user_of_employer_change(self):
1919
mail.send_mail("Update", "You now work for someone else!", [self.email])
2020
```
@@ -34,7 +34,7 @@ class UserAccount(LifecycleModel):
3434
email = models.CharField(max_length=600)
3535
employer = models.ForeignKey(Organization, on_delete=models.SET_NULL)
3636

37-
@hook(AFTER_UPDATE, when="employer.name", has_changed=True, is_now="Google")
37+
@hook(AFTER_UPDATE, condition=WhenFieldValueChangesTo("employer.name", value="Google"))
3838
def notify_user_of_google_buy_out(self):
3939
mail.send_mail("Update", "Google bought your employer!", ["to@example.com"],)
4040
```

docs/index.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,17 @@ class Article(LifecycleModel):
2020
status = models.ChoiceField(choices=['draft', 'published'])
2121
editor = models.ForeignKey(AuthUser)
2222

23-
@hook(BEFORE_UPDATE, when='contents', has_changed=True)
23+
@hook(BEFORE_UPDATE, condition=WhenFieldHasChanged('contents', has_changed=True))
2424
def on_content_change(self):
2525
self.updated_at = timezone.now()
2626

27-
@hook(AFTER_UPDATE, when="status", was="draft", is_now="published")
27+
@hook(
28+
AFTER_UPDATE,
29+
condition=(
30+
WhenFieldValueWas("status", value="draft")
31+
& WhenFieldValueIs("status", value="published")
32+
)
33+
)
2834
def on_publish(self):
2935
send_email(self.editor.email, "An article has published!")
3036
```
@@ -52,8 +58,8 @@ Instead of overriding `save` and `__init__` in a clunky way that hurts readabili
5258

5359
## Requirements
5460

55-
* Python (3.5+)
56-
* Django (2.0+)
61+
* Python (3.7+)
62+
* Django (2.2+)
5763

5864
## Installation
5965

0 commit comments

Comments
 (0)