source: telemeta/models/location.py @ 8cae994

cremcrem2devdev2diademsdj1.6feature/breadcrumbsfeature/ts-0.5feature/ts-0.5.4feature/writecacheformagenericinstru_searchlamlam2mapsv3mergenlivemultiproductionrelease/1.4.4sabiodsecurityserversocialstoragetelecastertestvideo
Last change on this file since 8cae994 was 8cae994, checked in by yomguy <yomguy@…>, 3 years ago

OAI fix : better id management (database id by default), split multiple coverage, repositoryName becomes settings.TELEMETA_ORGANIZATION

  • Property mode set to 100644
File size: 7.9 KB
Line 
1# -*- coding: utf-8 -*-
2# Copyright (C) 2007 Samalyse SARL
3
4# This software is a computer program whose purpose is to backup, analyse,
5# transcode and stream any audio content with its metadata over a web frontend.
6
7# This software is governed by the CeCILL  license under French law and
8# abiding by the rules of distribution of free software.  You can  use,
9# modify and/ or redistribute the software under the terms of the CeCILL
10# license as circulated by CEA, CNRS and INRIA at the following URL
11# "http://www.cecill.info".
12
13# As a counterpart to the access to the source code and  rights to copy,
14# modify and redistribute granted by the license, users are provided only
15# with a limited warranty  and the software's author,  the holder of the
16# economic rights,  and the successive licensors  have only  limited
17# liability.
18
19# In this respect, the user's attention is drawn to the risks associated
20# with loading,  using,  modifying and/or developing or reproducing the
21# software by the user in light of its specific status of free software,
22# that may mean  that it is complicated to manipulate,  and  that  also
23# therefore means  that it is reserved for developers  and  experienced
24# professionals having in-depth computer knowledge. Users are therefore
25# encouraged to load and test the software's suitability as regards their
26# requirements in conditions enabling the security of their systems and/or
27# data to be ensured and,  more generally, to use and operate it in the
28# same conditions as regards security.
29
30# The fact that you are presently reading this means that you have had
31# knowledge of the CeCILL license and that you accept its terms.
32#
33# Authors: Olivier Guilyardi <olivier@samalyse.com>
34#          David LIPSZYC <davidlipszyc@gmail.com>
35
36from telemeta.models.core import *
37from telemeta.util.unaccent import unaccent
38import re
39from django.db.models import Q
40from django.utils.translation import ugettext_lazy as _
41from telemeta.models.query import *
42from django.forms import ModelForm
43
44class Location(ModelCore):
45    "Locations"
46    OTHER_TYPE  = 0
47    CONTINENT   = 1
48    COUNTRY     = 2
49    TYPE_CHOICES     = ((COUNTRY, _('country')), (CONTINENT, _('continent')), (OTHER_TYPE, _('other')))
50
51    name             = CharField(_('name'), unique=True, max_length=150, required=True)
52    type             = IntegerField(_('type'), choices=TYPE_CHOICES, default=OTHER_TYPE, db_index=True)
53    complete_type    = ForeignKey('LocationType', related_name="locations", verbose_name=_('complete type'))
54    current_location = WeakForeignKey('self', related_name="past_names", 
55                                      verbose_name=_('current location')) 
56    latitude         = FloatField(null=True)                                   
57    longitude        = FloatField(null=True)                                   
58    is_authoritative = BooleanField(_('authoritative'))
59
60    objects = LocationManager()
61
62    def items(self):
63        from telemeta.models import MediaItem
64        return MediaItem.objects.by_location(self)
65
66    def collections(self):
67        from telemeta.models import MediaCollection
68        return MediaCollection.objects.by_location(self)
69
70    def ancestors(self, direct=False):
71        q = Q(descendant_relations__location=self)
72        if direct:
73            q &= Q(descendant_relations__is_direct=True)
74        return Location.objects.filter(q)           
75
76    def descendants(self, direct=False):
77        q = Q(ancestor_relations__ancestor_location=self)
78        if direct:
79            q &= Q(ancestor_relations__is_direct=True)
80        return Location.objects.filter(q)           
81
82    def apparented(self):
83        return Location.objects.filter(
84                Q(pk=self.id) | 
85                Q(ancestor_relations__ancestor_location=self) | 
86                Q(current_location=self.id)).distinct()
87
88    def add_child(self, other):
89        LocationRelation.objects.create(location=other, ancestor_location=self, is_direct=True)
90        for location in self.ancestors():
91            #FIXME: might raise Duplicate Entry
92            LocationRelation.objects.create(location=other, ancestor_location=location)
93           
94    def add_parent(self, other):
95        LocationRelation.objects.create(location=self, ancestor_location=other, is_direct=True)
96        for location in self.descendants():
97            #FIXME: might raise Duplicate Entry
98            LocationRelation.objects.create(location=location, ancestor_location=other)
99
100    def countries(self):
101        if self.type == self.COUNTRY:
102            return Location.objects.filter(pk=self.id)
103        return self.ancestors().filter(type=self.COUNTRY)
104
105    def continents(self):
106        if self.type == self.CONTINENT:
107            return Location.objects.filter(pk=self.id)
108        return self.ancestors().filter(type=self.CONTINENT)
109
110    class Meta(MetaCore):
111        db_table = 'locations'
112        verbose_name = _('location')
113        verbose_name_plural = _('locations')
114        ordering = ['name']
115
116    def __unicode__(self):
117        return self.name
118
119    def flatname(self):
120        if self.type != self.COUNTRY and self.type != self.CONTINENT:
121            raise Exception("Flat names are only supported for countries and continents")
122
123        map = Location.objects.flatname_map()
124        for flatname in map:
125            if self.id == map[flatname]:
126                return flatname
127
128        return None                   
129
130    def paths(self):
131        #FIXME: need to handle multiple (polyhierarchical) paths
132        path = []
133        location = self
134        while location:
135            path.append(location)
136            try:
137                location = location.ancestors(direct=True)[0]
138            except IndexError:
139                location = None
140        return [path]
141
142    def fullnames(self):
143        names = []
144        for path in self.paths():
145            names.append(u', '.join([unicode(l) for l in path]))
146        return names
147       
148    def listnames(self):
149        names = []
150        for path in self.paths():
151            for l in path:
152                names.append(unicode(l))
153        return names
154
155class LocationType(ModelCore):
156    "Location types"
157    code = CharField(_('identifier'), max_length=64, unique=True, required=True)
158    name = CharField(_('name'), max_length=150, required=True)
159
160    def __unicode__(self):
161        return self.name
162       
163    class Meta(MetaCore):
164        db_table = 'location_types'
165        ordering = ['name']
166
167class LocationAlias(ModelCore):
168    "Location aliases"
169    location         = ForeignKey('Location', related_name="aliases", verbose_name=_('location'))
170    alias            = CharField(_('alias'), max_length=150, required=True)
171    is_authoritative = BooleanField(_('authoritative'))
172
173    def __unicode__(self):
174        return self.alias
175
176    class Meta(MetaCore):
177        db_table = 'location_aliases'
178        unique_together = (('location', 'alias'),)
179        verbose_name_plural = _('location aliases')
180        ordering = ['alias']
181   
182class LocationRelation(ModelCore):
183    "Location relations"
184    location             = ForeignKey('Location', related_name="ancestor_relations", verbose_name=_('location'))
185    ancestor_location    = ForeignKey('Location', related_name="descendant_relations",  verbose_name=_('ancestor location'))
186    is_direct            = BooleanField(db_index=True)
187    is_authoritative = BooleanField(_('authoritative'))
188
189    class Meta(MetaCore):
190        db_table = 'location_relations'
191        unique_together = ('location', 'ancestor_location')
192        ordering = ['ancestor_location__name']
193
194    def __unicode__(self):
195        sep = ' > '
196        if not self.is_direct:
197            sep = ' >..> ' 
198        return unicode(self.ancestor_location) + sep + unicode(self.location)
199
200
201class LocationForm(ModelForm):
202    class Meta:
203        model = Location
204
205    def __init__(self, *args, **kwds):
206        super(LocationForm, self).__init__(*args, **kwds)
207#        self.fields['name'].queryset = Location.objects.order_by('name')
208       
Note: See TracBrowser for help on using the repository browser.