-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
16 changed files
with
229 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
Empty file.
9 changes: 9 additions & 0 deletions
9
src/open_producten/producttypes/management/commands/load_upl.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
from ..parsers import ParserCommand | ||
from ..utils import load_upn | ||
|
||
|
||
class Command(ParserCommand): | ||
plural_object_name = "upn" | ||
|
||
def handle(self, **options): | ||
super().handle(load_upn, **options) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import csv | ||
import logging | ||
import os | ||
from tempfile import NamedTemporaryFile | ||
from typing import Any, Dict, List | ||
|
||
from django.core.management import BaseCommand, CommandError | ||
|
||
import requests | ||
from lxml import etree | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
class ParserException(Exception): | ||
pass | ||
|
||
|
||
class OwmsParser: | ||
available_parsers = {"csv", "xml"} | ||
|
||
def __init__(self, xml_column_names=None): | ||
self.xml_column_names = xml_column_names | ||
|
||
def parse(self, filename: str): | ||
"""Call parsing function based on filename extension.""" | ||
|
||
_, extension = os.path.splitext(filename) | ||
file_format = extension[1:] | ||
|
||
if not filename.startswith("http"): | ||
return self.process_file(filename, file_format) | ||
|
||
with NamedTemporaryFile() as f: | ||
f.write(requests.get(filename).content) | ||
f.seek(0) | ||
return self.process_file(f.name, file_format) | ||
|
||
def process_file(self, filename, file_format): | ||
"""Process a given file, calling a specific method based on the given format.""" | ||
if file_format in self.available_parsers: | ||
return getattr(self, file_format)(filename) | ||
else: | ||
raise ParserException("File format does not exist") | ||
|
||
def xml(self, filename: str) -> List[Dict[str, Any]]: | ||
if not self.xml_column_names: | ||
raise ParserException("Invalid XML column names") | ||
|
||
tree = etree.parse(filename) | ||
values = tree.findall("value") | ||
return [ | ||
{ | ||
column: getattr(value.find(column), "text", None) | ||
for column in self.xml_column_names | ||
} | ||
for value in values | ||
] | ||
|
||
def csv(self, filename: str) -> List[Dict[str, Any]]: | ||
with open(filename, encoding="utf-8-sig") as f: | ||
data = csv.DictReader(f) | ||
return list(data) | ||
|
||
|
||
class ParserCommand(BaseCommand): | ||
plural_object_name = "objects" | ||
xml_column_names = None | ||
|
||
def __init__(self): | ||
self.help = ( | ||
f"Load {self.plural_object_name} to the database from a given XML/CSV file." | ||
) | ||
self.parser = OwmsParser(xml_column_names=self.xml_column_names) | ||
super().__init__() | ||
|
||
def add_arguments(self, parser): | ||
parser.add_argument( | ||
"filename", | ||
help="The name of the file to be imported.", | ||
) | ||
|
||
def handle(self, handler_function, **options): | ||
filename = options.pop("filename") | ||
|
||
self.stdout.write(f"Importing {self.plural_object_name} from {filename}...") | ||
|
||
try: | ||
data = self.parse(filename) | ||
created_count = handler_function(data) | ||
except Exception as e: | ||
self.stderr.write(f"Error: {e}") | ||
logger.exception(e) | ||
else: | ||
self.stdout.write(self.style.SUCCESS(f"Done ({created_count} objects).")) | ||
|
||
def parse(self, filename) -> List[Dict[str, Any]]: | ||
try: | ||
return self.parser.parse(filename) | ||
except ParserException: | ||
raise CommandError( | ||
f"No parser available for that format. Available: {', '.join(self.parser.available_parsers)}" | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import logging | ||
from typing import Any, Dict, List | ||
|
||
from open_producten.producttypes.models import UniformProductName | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
def load_upn(data: List[Dict[str, Any]]) -> int: | ||
""" | ||
Loads UPNs based on a list of dictionaries. | ||
""" | ||
count = 0 | ||
upn_updated_list = [] | ||
|
||
for obj in data: | ||
upn, created = UniformProductName.objects.update_or_create( | ||
uri=obj.get("URI"), | ||
defaults={"name": obj.get("UniformeProductnaam"), "is_deleted": False}, | ||
) | ||
upn_updated_list.append(upn.id) | ||
|
||
if created: | ||
count += 1 | ||
|
||
UniformProductName.objects.exclude(id__in=upn_updated_list).update( | ||
is_deleted=True, | ||
) | ||
return count |
45 changes: 45 additions & 0 deletions
45
src/open_producten/producttypes/migrations/0006_remove_uniformproductname_url_and_more.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
# Generated by Django 4.2.13 on 2024-09-27 13:48 | ||
|
||
from django.db import migrations, models | ||
|
||
|
||
class Migration(migrations.Migration): | ||
dependencies = [ | ||
("producttypes", "0005_producttype_contacts_producttype_locations_and_more"), | ||
] | ||
|
||
operations = [ | ||
migrations.RemoveField( | ||
model_name="uniformproductname", | ||
name="url", | ||
), | ||
migrations.AddField( | ||
model_name="uniformproductname", | ||
name="is_deleted", | ||
field=models.BooleanField( | ||
default=False, | ||
help_text="defines if the upn definition is deleted.", | ||
verbose_name="Is deleted", | ||
), | ||
), | ||
migrations.AddField( | ||
model_name="uniformproductname", | ||
name="uri", | ||
field=models.URLField( | ||
help_text="Uri to the upn definition.", | ||
unique=True, | ||
verbose_name="Uri", | ||
), | ||
preserve_default=False, | ||
), | ||
migrations.AlterField( | ||
model_name="uniformproductname", | ||
name="name", | ||
field=models.CharField( | ||
help_text="Uniform product name", | ||
max_length=100, | ||
unique=True, | ||
verbose_name="Name", | ||
), | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters