models.py 8.7 KB
Newer Older
luxcem's avatar
luxcem committed
1
2
# coding: utf-8

Jamesie Pic's avatar
Jamesie Pic committed
3
from datetime import datetime
luxcem's avatar
test    
luxcem committed
4

Yohan Boniface's avatar
Yohan Boniface committed
5
from django.db import models
Nicolas Joyard's avatar
Nicolas Joyard committed
6
from django.utils.encoding import smart_unicode
7
from django.utils.functional import cached_property
8
from memopol.utils import strip_accents
luxcem's avatar
luxcem committed
9

alexandre.jauneau's avatar
alexandre.jauneau committed
10

luxcem's avatar
luxcem committed
11
12
13
14
15
class TimeStampedModel(models.Model):
    """
    An abstract base class model that provides self-updating
    ``created`` and ``modified`` fields.
    """
16

luxcem's avatar
luxcem committed
17
18
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)
19

luxcem's avatar
luxcem committed
20
21
22
23
    class Meta:
        abstract = True


24
25
26
27
28
class CountryManager(models.Manager):
    def get_by_natural_key(self, code):
        return self.get(code=code)


Yohan Boniface's avatar
Yohan Boniface committed
29
class Country(models.Model):
30
31
    objects = CountryManager()

Yohan Boniface's avatar
Yohan Boniface committed
32
    name = models.CharField(max_length=255)
33
    code = models.CharField(max_length=2, unique=True)
Yohan Boniface's avatar
Yohan Boniface committed
34

Bram's avatar
Bram committed
35
    def __unicode__(self):
luxcem's avatar
test    
luxcem committed
36
        return u'{} [{}]'.format(self.name, self.code)
Bram's avatar
Bram committed
37

38
39
40
41
42
43
44
45
    def natural_key(self):
        return (self.code,)


class RepresentativeManager(models.Manager):
    def get_by_natural_key(self, slug):
        return self.get(slug=slug)

Yohan Boniface's avatar
Yohan Boniface committed
46

Nicolas Joyard's avatar
Nicolas Joyard committed
47
class Representative(TimeStampedModel):
luxcem's avatar
test    
luxcem committed
48
49
50
    """
    Base model for representatives
    """
51

52
53
    objects = RepresentativeManager()

54
    slug = models.SlugField(max_length=100, unique=True)
luxcem's avatar
luxcem committed
55
56
    first_name = models.CharField(max_length=255, blank=True, default='')
    last_name = models.CharField(max_length=255, blank=True, default='')
Yohan Boniface's avatar
Yohan Boniface committed
57
    full_name = models.CharField(max_length=255)
luxcem's avatar
test    
luxcem committed
58
59
60
61
62
    GENDER = (
        (0, "N/A"),
        (1, "F"),
        (2, "M"),
    )
63
    gender = models.SmallIntegerField(choices=GENDER, default=0)
luxcem's avatar
luxcem committed
64
    birth_place = models.CharField(max_length=255, blank=True, default='')
Yohan Boniface's avatar
Yohan Boniface committed
65
    birth_date = models.DateField(blank=True, null=True)
luxcem's avatar
luxcem committed
66
    cv = models.TextField(blank=True, default='')
luxcem's avatar
luxcem committed
67
    photo = models.CharField(max_length=512, null=True)
68
69
    active = models.BooleanField(default=False)

luxcem's avatar
luxcem committed
70
    def __unicode__(self):
71
        return smart_unicode(self.full_name)
luxcem's avatar
test    
luxcem committed
72

73
74
75
    def natural_key(self):
        return (self.slug,)

luxcem's avatar
luxcem committed
76
77
78
    def gender_as_str(self):
        genders = {0: 'N/A', 1: 'F', 2: 'M'}
        return genders[self.gender]
luxcem's avatar
luxcem committed
79

80
81
82
    def ascii_name(self):
        return strip_accents(self.full_name).lower()

83
84
    class Meta:
        ordering = ['last_name', 'first_name']
85

86
# Contact related models
87
88


luxcem's avatar
luxcem committed
89
class Contact(TimeStampedModel):
90
    representative = models.ForeignKey(Representative)
Yohan Boniface's avatar
Yohan Boniface committed
91
92
93
94
95
96
97

    class Meta:
        abstract = True


class Email(Contact):
    email = models.EmailField()
luxcem's avatar
luxcem committed
98
99
    kind = models.CharField(max_length=255, blank=True, default='')

Yohan Boniface's avatar
Yohan Boniface committed
100
101

class WebSite(Contact):
luxcem's avatar
luxcem committed
102
103
    url = models.CharField(max_length=2048, blank=True, default='')
    kind = models.CharField(max_length=255, blank=True, default='')
Yohan Boniface's avatar
Yohan Boniface committed
104
105


106
107
108
109
110
111
class AddressManager(models.Manager):
    def get_by_natural_key(self, name, kind, representative_slug):
        representative = Representative.objects.get(slug=representative_slug)
        return self.get(name=name, kind=kind, representative=representative)


Yohan Boniface's avatar
Yohan Boniface committed
112
class Address(Contact):
113
114
    objects = AddressManager()

Yohan Boniface's avatar
Yohan Boniface committed
115
    country = models.ForeignKey(Country)
luxcem's avatar
luxcem committed
116
117
118
119
120
121
122
123
    city = models.CharField(max_length=255, blank=True, default='')
    street = models.CharField(max_length=255, blank=True, default='')
    number = models.CharField(max_length=255, blank=True, default='')
    postcode = models.CharField(max_length=255, blank=True, default='')
    floor = models.CharField(max_length=255, blank=True, default='')
    office_number = models.CharField(max_length=255, blank=True, default='')
    kind = models.CharField(max_length=255, blank=True, default='')
    name = models.CharField(max_length=255, blank=True, default='')
124
    location = models.CharField(max_length=255, blank=True, default='')
luxcem's avatar
luxcem committed
125

126
127
128
129
    def natural_key(self):
        representative_nk = self.representative.natural_key()
        return (self.name, self.kind) + representative_nk

Yohan Boniface's avatar
Yohan Boniface committed
130
131

class Phone(Contact):
luxcem's avatar
luxcem committed
132
133
    number = models.CharField(max_length=255, blank=True, default='')
    kind = models.CharField(max_length=255, blank=True, default='')
luxcem's avatar
luxcem committed
134
    address = models.ForeignKey(Address, null=True, related_name='phones')
135

Yohan Boniface's avatar
Yohan Boniface committed
136

137
138
139
140
141
class ChamberManager(models.Manager):
    def get_by_natural_key(self, abbreviation):
        return self.get(abbreviation=abbreviation)


Nicolas Joyard's avatar
Nicolas Joyard committed
142
class Chamber(models.Model):
Nicolas Joyard's avatar
Nicolas Joyard committed
143
144
145
    """
    A representative chamber
    """
146
147
    objects = ChamberManager()

Nicolas Joyard's avatar
Nicolas Joyard committed
148
149
    name = models.CharField(max_length=255)
    country = models.ForeignKey('Country', null=True, related_name='chambers')
150
151
    abbreviation = models.CharField(max_length=10, blank=True, default='',
        db_index=True)
Nicolas Joyard's avatar
Nicolas Joyard committed
152

153
154
    def __unicode__(self):
        return u'{} [{}]'.format(self.name, self.abbreviation)
Nicolas Joyard's avatar
Nicolas Joyard committed
155

156
157
158
159
160
161
162
163
164
165
166
167
168
    def natural_key(self):
        return (self.abbreviation,)


class GroupManager(models.Manager):
    def get_by_natural_key(self, name, kind, chamber_nk):
        if chamber_nk:
            chamber = Chamber.objects.get_by_natural_key(chamber_nk)
        else:
            chamber = None

        return self.get(name=name, kind=kind, chamber=chamber)

Nicolas Joyard's avatar
Nicolas Joyard committed
169

Nicolas Joyard's avatar
Nicolas Joyard committed
170
class Group(TimeStampedModel):
171
    """
luxcem's avatar
luxcem committed
172
    An entity represented by a representative through a mandate
173
    """
174
175
    objects = GroupManager()

Nicolas Joyard's avatar
Nicolas Joyard committed
176
    name = models.CharField(max_length=511, db_index=True)
177
178
179
    abbreviation = models.CharField(max_length=10, blank=True, default='',
        db_index=True)
    kind = models.CharField(max_length=255, db_index=True)
Nicolas Joyard's avatar
Nicolas Joyard committed
180
    chamber = models.ForeignKey(Chamber, null=True, related_name='groups')
181

luxcem's avatar
test    
luxcem committed
182
183
184
185
    @cached_property
    def active(self):
        return self.mandates.filter(end_date__gte=datetime.now()).exists()

186
187
188
    def __unicode__(self):
        return unicode(self.name)

189
190
191
192
    def natural_key(self):
        chamber_nk = self.chamber.natural_key() if self.chamber else (None,)
        return (self.name, self.kind) + chamber_nk

193
194
195
    class Meta:
        ordering = ('name',)

196

197
198
199
200
201
202
203
204
205
206
class ConstituencyManager(models.Manager):
    def get_by_natural_key(self, name, country_nk):
        if country_nk:
            country = Country.objects.get_by_natural_key(country_nk)
        else:
            country = None

        return self.get(name=name, country=country)


Nicolas Joyard's avatar
Nicolas Joyard committed
207
class Constituency(TimeStampedModel):
208
    """
luxcem's avatar
luxcem committed
209
    An authority for which a representative has a mandate
210
    """
211
212
    objects = ConstituencyManager()

213
    name = models.CharField(max_length=255)
Jamesie Pic's avatar
Jamesie Pic committed
214
215
    country = models.ForeignKey('Country', null=True, blank=True,
        related_name='constituencies')
luxcem's avatar
luxcem committed
216

luxcem's avatar
test    
luxcem committed
217
218
219
    @cached_property
    def active(self):
        return self.mandates.filter(end_date__gte=datetime.now()).exists()
220
221

    def __unicode__(self):
luxcem's avatar
test    
luxcem committed
222
        return unicode(self.name)
223

224
225
226
227
    def natural_key(self):
        country_nk = self.country.natural_key() if self.country else (None,)
        return (self.name,) + country_nk

228

Arnaud Fabre's avatar
Arnaud Fabre committed
229
class MandateManager(models.Manager):
Jamesie Pic's avatar
Jamesie Pic committed
230
    """ This satisfies repr(Mandate) """
Arnaud Fabre's avatar
Arnaud Fabre committed
231
    def get_queryset(self):
232
233
234
235
236
237
        return super(
            MandateManager,
            self).get_queryset().select_related(
            'group',
            'constituency')

238
239
240
241
242
243
244
245
    def get_by_natural_key(self, begin_date, end_date, representative_slug,
                           group_name, group_kind, group_chamber_nk):
        representative = Representative.objects.get_by_natural_key(
            representative_slug)
        group = Group.objects.get_by_natural_key(group_name, group_kind,
                                                 group_chamber_nk)
        return self.get(begin_date=begin_date, end_date=end_date,
                        representative=representative, group=group)
Arnaud Fabre's avatar
Arnaud Fabre committed
246

247
248

class Mandate(TimeStampedModel):
Arnaud Fabre's avatar
Arnaud Fabre committed
249
    objects = MandateManager()
250

luxcem's avatar
luxcem committed
251
    group = models.ForeignKey(Group, null=True, related_name='mandates')
252
253
    constituency = models.ForeignKey(
        Constituency, null=True, related_name='mandates')
luxcem's avatar
luxcem committed
254
    representative = models.ForeignKey(Representative, related_name='mandates')
Yohan Boniface's avatar
Yohan Boniface committed
255
    role = models.CharField(
256
        max_length=255,
Yohan Boniface's avatar
Yohan Boniface committed
257
        blank=True,
luxcem's avatar
luxcem committed
258
        default='',
259
        help_text="Eg.: president of a political group"
Yohan Boniface's avatar
Yohan Boniface committed
260
261
262
    )
    begin_date = models.DateField(blank=True, null=True)
    end_date = models.DateField(blank=True, null=True)
luxcem's avatar
luxcem committed
263
264
    link = models.URLField()

luxcem's avatar
test    
luxcem committed
265
266
267
268
269
    @property
    def active(self):
        return self.end_date >= datetime.now().date()

    def __unicode__(self):
270
271
        t = u'Mandate : {representative},{role} {group} for {constituency}'
        return t.format(
luxcem's avatar
test    
luxcem committed
272
            representative=self.representative,
273
274
275
            role=(
                u' {} of'.format(
                    self.role) if self.role else u''),
luxcem's avatar
test    
luxcem committed
276
            constituency=self.constituency,
277
            group=self.group)
Jamesie Pic's avatar
Jamesie Pic committed
278

279
280
281
282
283
284
285
286
    def natural_key(self):
        rep_nk = self.representative.natural_key() \
            if self.representative else (None,)
        group_nk = self.group.natural_key() \
            if self.group else (None, None, None)

        return (self.begin_date, self.end_date) + rep_nk + group_nk

Jamesie Pic's avatar
Jamesie Pic committed
287
288
    class Meta:
        ordering = ('-end_date',)