Projet

Général

Profil

0001-base_adresses-work-around-missing-departments-and-re.patch

Benjamin Dauvergne, 27 juin 2022 15:30

Télécharger (7,71 ko)

Voir les différences:

Subject: [PATCH] base_adresses: work around missing departments and regions in
 generic api.geo files (#66625)

 .../migrations/0030_auto_20220627_1511.py     |  18 +++
 passerelle/apps/base_adresse/models.py        | 107 +++++++++++++-----
 2 files changed, 94 insertions(+), 31 deletions(-)
 create mode 100644 passerelle/apps/base_adresse/migrations/0030_auto_20220627_1511.py
passerelle/apps/base_adresse/migrations/0030_auto_20220627_1511.py
1
# Generated by Django 2.2.28 on 2022-06-27 13:11
2

  
3
from django.db import migrations, models
4

  
5

  
6
class Migration(migrations.Migration):
7

  
8
    dependencies = [
9
        ('base_adresse', '0029_auto_20220624_0827'),
10
    ]
11

  
12
    operations = [
13
        migrations.AlterField(
14
            model_name='regionmodel',
15
            name='code',
16
            field=models.CharField(max_length=3, verbose_name='Region code'),
17
        ),
18
    ]
passerelle/apps/base_adresse/models.py
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
......
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
        }
516
        regions = {}
517
        departements = {}
518

  
519
        def get_region(code_region):
520
            if code_region not in regions:
521
                data = regions_json.get(code_region) or self.get_api_geo_endpoint(f'regions/{code_region}')
522
                region, created = self.regionmodel_set.get_or_create(
523
                    code=data['code'], defaults={'name': data['nom']}
524
                )
525
                if not created and region.name != data['nom']:
526
                    region.name = data['nom']
527
                    region.save()
528
                regions[code_region] = region
529
            return regions[code_region]
530

  
531
        def get_departement(code_departement):
532
            if code_departement not in departements:
533
                data = departements_json.get(code_departement) or self.get_api_geo_endpoint(
534
                    f'departements/{code_departement}'
535
                )
536
                region = get_region(data['codeRegion'])
537
                departement, created = self.departmentmodel_set.get_or_create(
538
                    code=data['code'], defaults={'name': data['nom'], 'region': region}
539
                )
540
                if not created and departement.name != data['nom'] or departement.region != region:
541
                    departement.name = data['nom']
542
                    departement.region = region
543
                    departement.save()
544
                departements[code_departement] = departement
545
            return departements[code_departement]
546

  
547
        def grouper(it, size):
548
            '''Split iterator in equal size chunk of `size` elements.'''
549
            it = iter(it)
550
            return iter(lambda: tuple(itertools.islice(it, size)), ())
551

  
552
        city_pks = set()
513 553
        cities_json = self.get_api_geo_endpoint('communes')
514
        if not (regions_json and departments_json and cities_json):
554
        if not cities_json:
515 555
            return
516
        start_update = timezone.now()
517

  
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()
524 556

  
525
        for data in departments_json:
526
            defaults = {
527
                'name': data['nom'],
528
                'region': self.regionmodel_set.get(code=data['codeRegion']),
557
        for batch_data in grouper(cities_json, 1000):
558
            cities = {
559
                (city.code, city.zipcode): city
560
                for city in self.citymodel_set.filter(code__in=[x['code'] for x in batch_data])
529 561
            }
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()
562
            for data in list(batch_data):
563
                for zipcode in data['codesPostaux']:
564
                    defaults = {
565
                        'name': data['nom'],
566
                        'population': data.get('population', 0),
567
                    }
568
                    if data.get('codeDepartement'):
569
                        defaults['department'] = get_departement(data['codeDepartement'])
570
                    if data.get('codeRegion'):
571
                        defaults['region'] = get_region(data['codeRegion'])
572
                    if (data['code'], zipcode) in cities:
573
                        city, created = cities[(data['code'], zipcode)], False
574
                    else:
575
                        city, created = self.citymodel_set.get_or_create(
576
                            code=data['code'], zipcode=zipcode, defaults=defaults
577
                        )
578
                    if not created and any(
579
                        getattr(city, key) != defaults.get(key)
580
                        for key in ['name', 'population', 'department', 'region']
581
                    ):
582
                        for key in ['name', 'population', 'department', 'region']:
583
                            setattr(city, key, defaults.get(key))
584
                        city.save()
585
                    city_pks.add(city.pk)
586

  
587
        self.regionmodel_set.exclude(code__in=regions.keys()).delete()
588
        self.departmentmodel_set.exclude(code__in=departements.keys()).delete()
589
        self.citymodel_set.exclude(pk__in=city_pks).delete()
545 590

  
546 591
    def clean_addresses_cache(self):
547 592
        old_addresses = self.addresscachemodel_set.filter(
......
597 642

  
598 643
    name = models.CharField(_('Region name'), max_length=150)
599 644
    unaccent_name = models.CharField(_('Region name ascii char'), max_length=150, null=True)
600
    code = models.CharField(_('Region code'), max_length=2)
645
    code = models.CharField(_('Region code'), max_length=3)
601 646
    last_update = models.DateTimeField(_('Last update'), null=True, auto_now=True)
602 647

  
603 648
    resource = models.ForeignKey(BaseAdresse, on_delete=models.CASCADE, verbose_name=_('BAN Connector'))
604
-