-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathkladdress.py
More file actions
187 lines (168 loc) · 6.69 KB
/
kladdress.py
File metadata and controls
187 lines (168 loc) · 6.69 KB
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# -*- coding: utf-8 -*-
from django.db.models import Q
from kladr.models import *
import logging
log = logging.getLogger(__name__)
def singleton(cls):
instances = {}
def getinstance():
if cls not in instances:
instances[cls] = cls()
return instances[cls]
return getinstance
@singleton
class Kladdress():
"""
Класс для работы с КЛАДРом
@author: serge <serge@shtripling.com>
@todo: альтернативыне имена
"""
#Значения типов соответствуют описанию КЛАДРа
types={ 'region': 1,
'district': 2,
'city': 3,
'ville': 4,
'street': 5,
'house': 6,
'undef': -1
}
def _get_class(self, type):
classes = {
self.types['region']: Region,
self.types['district']: District,
self.types['city']: City,
self.types['ville']: Ville,
self.types['street']: Street,
self.types['house']: House
}
try:
return classes[type]
except (KeyError, IndexError):
return None
def _level_offset(self,lvl):
o = [0, 0, 2, 5, 8, 11, 15]
try:
return o[lvl]
except IndexError:
log.error(u'requested wrong KLADR level')
return 0
def _seek_altname(self,code):
return code
def _get_code_by_lvl(self,code,lvl,strip_zeros=False):
offset = self._level_offset(lvl+1)
strip_zeros = 0 if strip_zeros else 1
return u'%s%s' % (code[:offset],'0'*(len(code)-offset)*strip_zeros)
def _get_children_code_mask(self, code, lvl=None):
"""Формирует маску для поиска кода объектов нижнего уровня для code
@todo: учёт статуса и альтернативных имён
"""
if not lvl:
lvl = self._calc_level(code)
offset = self._level_offset(lvl + 1) #маскировать будем детей
return u'%s%s' % (code[:offset],'')#'0'*(len(code)-offset))
def _check_if_nzeros(self,s):
try:
i = int(s)
except ValueError:
return False
else:
return i != 0
def _calc_level(self, code=None ):
if not code:
return self.types['undef']
## @todo раскурить что за фигня с кодом дома/улицы
if self._check_if_nzeros(code[14:17]): return self.types['street']#self.types['house']
if self._check_if_nzeros(code[11:14]): return self.types['street']
if self._check_if_nzeros(code[8:11]): return self.types['ville']
if self._check_if_nzeros(code[5:8]): return self.types['city']
if self._check_if_nzeros(code[2:5]): return self.types['district']
return self.types['region']
def get_list(self, parent=None, name_starts=''):
"""
Получает список объектов
@param parent string - код вышестоящего объекта.
@return list
"""
lvl = self._calc_level(parent)
if not parent:
p_level = 1 #детишки
else:
p_level = lvl + 1
r = []
if parent:
#Ищем, не устаревший ли код.
if parent[-2:] != '00':
parent = self._seek_altname(parent)
list = self._get_class(p_level).objects.filter(
Q(code__startswith=self._get_children_code_mask(parent)),
Q(name__istartswith=name_starts)
)
[r.append(x) for x in list]
if lvl in (self.types['region'], self.types['district'], self.types['city']): # на уровне района ищем и города, и посёлки.
list=self._get_class(p_level+1).objects.filter(
Q(code__startswith=self._get_children_code_mask(parent)),
Q(code__startswith=self._get_children_code_mask(parent, p_level)),#избегаем включения через уровень.
Q(name__istartswith=name_starts)
)
[r.append(x) for x in list]
else:
list = self._get_class(p_level).objects.filter(Q(name__istartswith=name_starts) )
[r.append(x) for x in list]
if lvl in (self.types['region'], self.types['district'], self.types['city']):
#list.append(classes[p_level+1].objects.all())
list = self._get_class(p_level+1).objects.filter(Q(name__istartswith=name_starts) )
[r.append(x) for x in list]
return r
def get_name(self, code=None):
"""
Получает полное название геграфического объекта
"""
if not code:
return ''
lvl = self._calc_level(code)
o_class = self._get_class(lvl)
try:
obj = o_class.objects.get(code=code)
except o_class.DoesNotExist:
log.warn(u'%s code requested not found')
return code
r = []
c = []
for t_ in range(lvl-1):
t_lvl = t_ + 1
t_code = self._get_code_by_lvl(code, t_lvl, True)
t_class = self._get_class(t_lvl)
try:
t_obj = t_class.objects.get(code__startswith=t_code)
except t_class.DoesNotExist:
pass
else:
r.append(t_obj.__str__()) #u'{} {},'.format(r, t_obj)
c.append(t_obj.code)
# r = u'{} {}'.format(r, obj)
r.append(obj.__str__())
r = {'name':', '.join(r), 'codes': c}
return r
def get_codes_by_name(self, name, level=None, parent=None):
results = []
if name==u'Азовский':
name= u'Азовский немецкий национальный'
try:
if not parent:
if level:
t = self._get_class(level)
results = t.objects.filter(name=name).all()
else:
for i in self.types:
if self.types[i]<0 : continue
t = self._get_class(self.types[i]).objects.filter(name__istartswith=name).all()
[results.append(e) for e in t]
else:
l = self.get_list(parent)
for i in l:
if i.name==name:
results.append(i)
except AttributeError:
pass
return results
#from kladr.kladdress import Kladdress; o = Kladdress().get_list('5500000000000')