From 9aeaceaab33ed95af8fcfd513fb0f4ad0a6529f6 Mon Sep 17 00:00:00 2001 From: Gabriel Augendre Date: Sat, 29 Oct 2022 11:03:23 +0200 Subject: [PATCH] Partial path import --- src/character/admin.py | 9 ++- .../management/commands/import_paths.py | 80 +++++++++++++++++++ .../migrations/0006_alter_path_category.py | 26 ++++++ src/character/migrations/max_migration.txt | 2 +- src/character/models/capabilities.py | 1 + 5 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 src/character/management/commands/import_paths.py create mode 100644 src/character/migrations/0006_alter_path_category.py diff --git a/src/character/admin.py b/src/character/admin.py index 378696d..dd293c1 100644 --- a/src/character/admin.py +++ b/src/character/admin.py @@ -38,11 +38,18 @@ class RacialCapabilityAdmin(admin.ModelAdmin): search_fields = ["name", "description"] +class PathInline(admin.TabularInline): + model = models.Path + fields = ["name"] + extra = 0 + + @admin.register(models.Profile) class ProfileAdmin(admin.ModelAdmin): list_display = ["name", "life_dice", "magical_strength"] list_filter = ["life_dice", "magical_strength"] search_fields = ["name"] + inlines = [PathInline] class RacialCapabilityInline(admin.TabularInline): @@ -54,7 +61,7 @@ class RacialCapabilityInline(admin.TabularInline): class RaceAdmin(admin.ModelAdmin): list_display = ["name"] search_fields = ["name"] - inlines = [RacialCapabilityInline] + inlines = [RacialCapabilityInline, PathInline] @admin.register(models.Character) diff --git a/src/character/management/commands/import_paths.py b/src/character/management/commands/import_paths.py new file mode 100644 index 0000000..532d052 --- /dev/null +++ b/src/character/management/commands/import_paths.py @@ -0,0 +1,80 @@ +from django.core.management import BaseCommand +from selenium import webdriver +from selenium.webdriver.common.by import By + +from character.models import Path, Profile, Race + + +class Command(BaseCommand): + def handle(self, *args, **options): + url = "https://www.co-drs.org/fr/jeu/voies" + self.setup_selenium() + self.selenium.get(url) + anchors = self.selenium.find_elements( + By.CSS_SELECTOR, ".card-body .card-title a" + ) + urls = [anchor.get_attribute("href") for anchor in anchors] + for url in urls: + try: + self.import_path(url) + except Exception as e: + print(f"{type(e)}: {e}") + self.stdout.write(f"Finished processing {len(urls)} paths.") + + def import_path(self, url: str): + self.selenium.get(url) + name = self.selenium.find_element(By.TAG_NAME, "h1").text + category = self.get_category(name) + profile = None + if category == Path.Category.PROFILE: + profile = self.get_profile() + race = None + if category == Path.Category.RACE: + profile = self.get_race(name) + + path, _ = Path.objects.update_or_create( + name=name, + defaults={"category": category, "profile": profile, "race": race}, + ) + self.stdout.write(self.style.SUCCESS(f"Created/updated path {path}")) + + def get_category(self, name: str) -> Path.Category | None: + try: + category = ( + self.selenium.find_element( + By.CSS_SELECTOR, ".field--name-type .field__item" + ) + .text.lower() + .strip() + ) + except Exception: + self.stdout.write( + self.style.WARNING( + f"Couldn't find category for {name}. Defaulting to profile." + ) + ) + return Path.Category.PROFILE + + if category == "personnage": + return Path.Category.PROFILE + if category == "créature": + return Path.Category.CREATURE + return Path.Category(category) + + def get_profile(self) -> Profile: + profile_name = self.selenium.find_element( + By.CSS_SELECTOR, ".field--name-type + strong + a" + ).text + return Profile.objects.get_by_natural_key(profile_name) + + def get_race(self, path_name: str) -> Race: + return None + to_remove = [""] + for text in to_remove: + path_name = path_name.replace(text, "") + return Race.objects.get(name__iexact=path_name) + + def setup_selenium(self): + options = webdriver.FirefoxOptions() + options.add_argument("-headless") + self.selenium = webdriver.Firefox(options=options) diff --git a/src/character/migrations/0006_alter_path_category.py b/src/character/migrations/0006_alter_path_category.py new file mode 100644 index 0000000..de408ae --- /dev/null +++ b/src/character/migrations/0006_alter_path_category.py @@ -0,0 +1,26 @@ +# Generated by Django 4.1.2 on 2022-10-29 08:49 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("character", "0005_profile_notes_alter_character_mana_consumed_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="path", + name="category", + field=models.CharField( + choices=[ + ("profile", "Profile"), + ("race", "Race"), + ("prestige", "Prestige"), + ("creature", "Creature"), + ], + max_length=20, + ), + ), + ] diff --git a/src/character/migrations/max_migration.txt b/src/character/migrations/max_migration.txt index 65eae75..c04a8d9 100644 --- a/src/character/migrations/max_migration.txt +++ b/src/character/migrations/max_migration.txt @@ -1 +1 @@ -0005_profile_notes_alter_character_mana_consumed_and_more +0006_alter_path_category diff --git a/src/character/models/capabilities.py b/src/character/models/capabilities.py index 5174beb..df68a05 100644 --- a/src/character/models/capabilities.py +++ b/src/character/models/capabilities.py @@ -25,6 +25,7 @@ class Path(UniquelyNamedModel, TimeStampedModel, models.Model): PROFILE = "profile", "Profile" RACE = "race", "Race" PRESTIGE = "prestige", "Prestige" + CREATURE = "creature", "Creature" category = models.CharField(max_length=20, choices=Category.choices) notes = models.TextField(blank=True)