File: models.py

package info (click to toggle)
django-fsm-admin 1.2.5-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 220 kB
  • sloc: python: 425; makefile: 36
file content (113 lines) | stat: -rw-r--r-- 3,456 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
from django.db import models
from django.utils import timezone

from django_fsm import FSMField, transition


class State(object):
    '''
    Constants to represent the `state`s of the PublishableModel
    '''
    DRAFT = 'draft'            # Early stages of content editing
    APPROVED = 'approved'      # Ready to be published
    PUBLISHED = 'published'    # Visible on the website
    EXPIRED = 'expired'        # Period for which the model is set to display has passed
    DELETED = 'deleted'        # Soft delete state

    CHOICES = (
        (DRAFT, DRAFT),
        (APPROVED, APPROVED),
        (PUBLISHED, PUBLISHED),
        (EXPIRED, EXPIRED),
        (DELETED, DELETED),
    )


class PublishableModel(models.Model):

    name = models.CharField(max_length=42, blank=False)

    # One state to rule them all
    state = FSMField(
        default=State.DRAFT,
        verbose_name='Publication State',
        choices=State.CHOICES,
        protected=True,
    )

    # For scheduled publishing
    display_from = models.DateTimeField(blank=True, null=True)
    display_until = models.DateTimeField(blank=True, null=True)

    class Meta:
        verbose_name = 'Post'
        verbose_name_plural = 'Posts'

    def __unicode__(self):
        return self.name

    ########################################################
    # Transition Conditions
    # These must be defined prior to the actual transitions
    # to be refrenced.

    def has_display_dates(self):
        return self.display_from and self.display_until
    has_display_dates.hint = 'Display dates are required to expire a page.'

    def can_display(self):
        '''
        The display dates must be valid for the current date
        '''
        return self.check_displayable(timezone.now())
    can_display.hint = 'The display dates may need to be adjusted.'

    def is_expired(self):
        return self.state == State.EXPIRED

    def check_displayable(self, date):
        '''
        Check that the current date falls within this object's display dates,
        if set, otherwise default to being displayable.
        '''
        if not self.has_display_dates():
            return True

        displayable = self.display_from < date and self.display_until > date
        # Expired Pages should transition to the expired state
        if not displayable and not self.is_expired:
            self.expire()  # Calling the expire transition
            self.save()
        return displayable

    ########################################################
    # Workflow (state) Transitions

    @transition(field=state, source=[State.APPROVED, State.EXPIRED],
        target=State.PUBLISHED,
        conditions=[can_display])
    def publish(self):
        '''
        Publish the object.
        '''

    @transition(field=state, source=State.PUBLISHED, target=State.EXPIRED,
        conditions=[has_display_dates])
    def expire(self):
        '''
        Automatically called when a object is detected as being not
        displayable. See `check_displayable`
        '''
        self.display_until = timezone.now()

    @transition(field=state, source=State.PUBLISHED, target=State.APPROVED)
    def unpublish(self):
        '''
        Revert to the approved state
        '''

    @transition(field=state, source=State.DRAFT, target=State.APPROVED)
    def approve(self):
        '''
        After reviewed by stakeholders, the Page is approved.
        '''