1 |
1 |
import datetime
|
2 |
2 |
import gzip
|
|
3 |
import itertools
|
3 |
4 |
import json
|
4 |
5 |
from io import StringIO
|
5 |
6 |
from urllib import parse as urlparse
|
... | ... | |
502 |
503 |
error = 'invalid json, got: %s' % response.text
|
503 |
504 |
if error:
|
504 |
505 |
self.logger.error('failed to update api geo data for endpoint %s: %s', endpoint, error)
|
505 |
|
return
|
|
506 |
return {}
|
506 |
507 |
if not result:
|
507 |
508 |
raise Exception('api geo returns empty json')
|
508 |
509 |
return result
|
509 |
510 |
|
510 |
511 |
def update_api_geo_data(self):
|
511 |
|
regions_json = self.get_api_geo_endpoint('regions')
|
512 |
|
departments_json = self.get_api_geo_endpoint('departements')
|
|
512 |
regions_json = {region['code']: region for region in self.get_api_geo_endpoint('regions')}
|
|
513 |
departements_json = {
|
|
514 |
departement['code']: departement for departement in self.get_api_geo_endpoint('departements')
|
|
515 |
}
|
513 |
516 |
cities_json = self.get_api_geo_endpoint('communes')
|
514 |
|
if not (regions_json and departments_json and cities_json):
|
|
517 |
|
|
518 |
if not regions_json or not departements_json or not cities_json:
|
515 |
519 |
return
|
516 |
|
start_update = timezone.now()
|
517 |
520 |
|
518 |
|
for data in regions_json:
|
519 |
|
defaults = {
|
520 |
|
'name': data['nom'],
|
521 |
|
}
|
522 |
|
self.regionmodel_set.update_or_create(code=data['code'], defaults=defaults)
|
523 |
|
self.regionmodel_set.filter(last_update__lt=start_update).delete()
|
|
521 |
regions = {}
|
|
522 |
departements = {}
|
524 |
523 |
|
525 |
|
for data in departments_json:
|
526 |
|
defaults = {
|
527 |
|
'name': data['nom'],
|
528 |
|
'region': self.regionmodel_set.get(code=data['codeRegion']),
|
|
524 |
def get_region(code_region):
|
|
525 |
if code_region not in regions:
|
|
526 |
data = regions_json.get(code_region) or self.get_api_geo_endpoint(f'regions/{code_region}')
|
|
527 |
if not data:
|
|
528 |
return None
|
|
529 |
region, created = self.regionmodel_set.get_or_create(
|
|
530 |
code=data['code'], defaults={'name': data['nom']}
|
|
531 |
)
|
|
532 |
if not created and region.name != data['nom']:
|
|
533 |
region.name = data['nom']
|
|
534 |
region.save()
|
|
535 |
regions[code_region] = region
|
|
536 |
return regions[code_region]
|
|
537 |
|
|
538 |
def get_departement(code_departement):
|
|
539 |
if code_departement not in departements:
|
|
540 |
data = departements_json.get(code_departement) or self.get_api_geo_endpoint(
|
|
541 |
f'departements/{code_departement}'
|
|
542 |
)
|
|
543 |
if not data:
|
|
544 |
return None
|
|
545 |
region = get_region(data['codeRegion'])
|
|
546 |
departement, created = self.departmentmodel_set.get_or_create(
|
|
547 |
code=data['code'], defaults={'name': data['nom'], 'region': region}
|
|
548 |
)
|
|
549 |
if not created and departement.name != data['nom'] or departement.region != region:
|
|
550 |
departement.name = data['nom']
|
|
551 |
departement.region = region
|
|
552 |
departement.save()
|
|
553 |
departements[code_departement] = departement
|
|
554 |
return departements[code_departement]
|
|
555 |
|
|
556 |
for code_region in regions_json:
|
|
557 |
get_region(code_region)
|
|
558 |
|
|
559 |
for code_departement in departements_json:
|
|
560 |
get_departement(code_departement)
|
|
561 |
|
|
562 |
def grouper(it, size):
|
|
563 |
'''Split iterator in equal size chunk of `size` elements.'''
|
|
564 |
it = iter(it)
|
|
565 |
return iter(lambda: tuple(itertools.islice(it, size)), ())
|
|
566 |
|
|
567 |
city_pks = set()
|
|
568 |
|
|
569 |
for batch_data in grouper(cities_json, 1000):
|
|
570 |
batch_data = list(batch_data)
|
|
571 |
cities = {
|
|
572 |
(city.code, city.zipcode): city
|
|
573 |
for city in self.citymodel_set.filter(code__in=[x['code'] for x in batch_data])
|
529 |
574 |
}
|
530 |
|
self.departmentmodel_set.update_or_create(code=data['code'], defaults=defaults)
|
531 |
|
self.departmentmodel_set.filter(last_update__lt=start_update).delete()
|
532 |
|
|
533 |
|
for data in cities_json:
|
534 |
|
for zipcode in data['codesPostaux']:
|
535 |
|
defaults = {
|
536 |
|
'name': data['nom'],
|
537 |
|
'population': data.get('population', 0),
|
538 |
|
}
|
539 |
|
if data.get('codeDepartement'):
|
540 |
|
defaults['department'] = self.departmentmodel_set.get(code=data['codeDepartement'])
|
541 |
|
if data.get('codeRegion'):
|
542 |
|
defaults['region'] = self.regionmodel_set.get(code=data['codeRegion'])
|
543 |
|
self.citymodel_set.update_or_create(code=data['code'], zipcode=zipcode, defaults=defaults)
|
544 |
|
self.citymodel_set.filter(last_update__lt=start_update).delete()
|
|
575 |
for data in batch_data:
|
|
576 |
for zipcode in data['codesPostaux']:
|
|
577 |
defaults = {
|
|
578 |
'name': data['nom'],
|
|
579 |
'population': data.get('population', 0),
|
|
580 |
}
|
|
581 |
if data.get('codeDepartement'):
|
|
582 |
departement = get_departement(data['codeDepartement'])
|
|
583 |
if not departement:
|
|
584 |
continue
|
|
585 |
defaults['department'] = departement
|
|
586 |
if data.get('codeRegion'):
|
|
587 |
region = get_region(data['codeRegion'])
|
|
588 |
if not region:
|
|
589 |
continue
|
|
590 |
defaults['region'] = region
|
|
591 |
if (data['code'], zipcode) in cities:
|
|
592 |
city, created = cities[(data['code'], zipcode)], False
|
|
593 |
else:
|
|
594 |
city, created = self.citymodel_set.get_or_create(
|
|
595 |
code=data['code'], zipcode=zipcode, defaults=defaults
|
|
596 |
)
|
|
597 |
if not created and any(
|
|
598 |
getattr(city, key) != defaults.get(key)
|
|
599 |
for key in ['name', 'population', 'department', 'region']
|
|
600 |
):
|
|
601 |
for key in ['name', 'population', 'department', 'region']:
|
|
602 |
setattr(city, key, defaults.get(key))
|
|
603 |
city.save()
|
|
604 |
city_pks.add(city.pk)
|
|
605 |
|
|
606 |
self.regionmodel_set.exclude(code__in=regions.keys()).delete()
|
|
607 |
self.departmentmodel_set.exclude(code__in=departements.keys()).delete()
|
|
608 |
self.citymodel_set.exclude(pk__in=city_pks).delete()
|
545 |
609 |
|
546 |
610 |
def clean_addresses_cache(self):
|
547 |
611 |
old_addresses = self.addresscachemodel_set.filter(
|
... | ... | |
597 |
661 |
|
598 |
662 |
name = models.CharField(_('Region name'), max_length=150)
|
599 |
663 |
unaccent_name = models.CharField(_('Region name ascii char'), max_length=150, null=True)
|
600 |
|
code = models.CharField(_('Region code'), max_length=2)
|
|
664 |
code = models.CharField(_('Region code'), max_length=3)
|
601 |
665 |
last_update = models.DateTimeField(_('Last update'), null=True, auto_now=True)
|
602 |
666 |
|
603 |
667 |
resource = models.ForeignKey(BaseAdresse, on_delete=models.CASCADE, verbose_name=_('BAN Connector'))
|
604 |
|
-
|