diff --git a/README.md b/README.md index d90b5b1..0ed9a13 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,8 @@ Website for Python Ireland (python.ie / pycon.ie) community, built with Django 6 4. Generate sample data (creates pages, navigation, meetups): ```bash - docker compose run --rm web python pythonie/manage.py generate_sample_data --settings=pythonie.settings.dev + task django:generate-sample-data + # or: docker compose run --rm web python pythonie/manage.py generate_sample_data --settings=pythonie.settings.dev ``` 5. Create a superuser: @@ -58,7 +59,7 @@ If you prefer to develop without Docker: 5. Activate the virtualenv: `source pythonie-venv/bin/activate` 6. Install dependencies: `pip install -r requirements.txt` (or `uv pip install -r requirements.txt`) 7. Set up the database: `python pythonie/manage.py migrate --settings=pythonie.settings.dev` -8. Generate sample data: `python pythonie/manage.py generate_sample_data --settings=pythonie.settings.dev` +8. Generate sample data: `task django:generate-sample-data` (or `python pythonie/manage.py generate_sample_data --settings=pythonie.settings.dev`) 9. Create a superuser: `python pythonie/manage.py createsuperuser --settings=pythonie.settings.dev` 10. Install and run Redis server locally: `redis-server` 11. Set Redis environment variable: `export REDISCLOUD_URL=127.0.0.1:6379` @@ -95,7 +96,7 @@ task django:make-migrations # Create new migrations task django:collect-static # Collect static files # Sample Data (for development) -python pythonie/manage.py generate_sample_data --settings=pythonie.settings.dev +task django:generate-sample-data # Testing task tests # Run test suite diff --git a/Taskfile.yaml b/Taskfile.yaml index 09a68eb..be24ecb 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -145,6 +145,16 @@ tasks: cmds: - docker compose run --rm web python pythonie/manage.py collectstatic + django:generate-sample-data: + desc: Generate sample data for development + cmds: + - | + if command -v docker >/dev/null 2>&1 && docker ps >/dev/null 2>&1; then + docker compose run --rm web python pythonie/manage.py generate_sample_data + else + python pythonie/manage.py generate_sample_data --settings=pythonie.settings.dev + fi + dependencies:compute: desc: Compute the dependencies cmds: diff --git a/development.env b/development.env new file mode 100644 index 0000000..94ad002 --- /dev/null +++ b/development.env @@ -0,0 +1,7 @@ +DJANGO_SETTINGS_MODULE=pythonie.settings.dev +PGDATABASE=pythonie +PGUSER=postgres +PGPASSWORD=pythonie +PGHOST=postgres +REDISCLOUD_URL=redis://redis:6379 + diff --git a/pythonie/core/factories.py b/pythonie/core/factories.py index 1ae74f1..1c57d2d 100644 --- a/pythonie/core/factories.py +++ b/pythonie/core/factories.py @@ -1,10 +1,11 @@ import factory from django.utils import timezone from factory.django import DjangoModelFactory -from meetups.models import Meetup -from sponsors.models import SponsorshipLevel +import wagtail_factories from core.models import HomePage, SimplePage +from meetups.models import Meetup +from sponsors.models import SponsorshipLevel class SponsorshipLevelFactory(DjangoModelFactory): @@ -32,7 +33,7 @@ class Meta: visibility = "public" -class HomePageFactory(DjangoModelFactory): +class HomePageFactory(wagtail_factories.PageFactory): class Meta: model = HomePage @@ -42,7 +43,7 @@ class Meta: body = [] -class SimplePageFactory(DjangoModelFactory): +class SimplePageFactory(wagtail_factories.PageFactory): class Meta: model = SimplePage diff --git a/pythonie/core/management/commands/generate_sample_data.py b/pythonie/core/management/commands/generate_sample_data.py index 905ad6e..a8c32fd 100644 --- a/pythonie/core/management/commands/generate_sample_data.py +++ b/pythonie/core/management/commands/generate_sample_data.py @@ -41,23 +41,47 @@ def _create_home_page(self): self.stdout.write("Home page already exists") return home - wagtail_root = Page.objects.get(depth=1) + try: + wagtail_root = Page.objects.get(depth=1) + except Page.DoesNotExist: + from wagtail.models import Locale + + locale, _ = Locale.objects.get_or_create(language_code="en") + wagtail_root = Page.add_root( + instance=Page(title="Root", slug="root", locale=locale) + ) + self.stdout.write("Created Wagtail root page") + default_home_exists = Page.objects.filter(slug="home", depth=2).exists() slug = "python-ireland" if default_home_exists else "home" - home = HomePageFactory.build( + home = HomePageFactory( + parent=wagtail_root, slug=slug, show_in_menus=True, body=self._get_home_content(), ) - wagtail_root.add_child(instance=home) - self.stdout.write(self.style.SUCCESS("Created home page")) - - site = Site.objects.filter(is_default_site=True).first() - if site: + # Publish the home page + revision = home.save_revision() + revision.publish() + self.stdout.write(self.style.SUCCESS("Created and published home page")) + + # Create or update the default site + site, created = Site.objects.get_or_create( + is_default_site=True, + defaults={ + "hostname": "localhost", + "port": 8000, + "site_name": "Python Ireland", + "root_page": home, + }, + ) + if not created: site.root_page = home site.save() self.stdout.write(self.style.SUCCESS("Updated site root page")) + else: + self.stdout.write(self.style.SUCCESS("Created default site")) return home @@ -88,10 +112,13 @@ def _create_page(self, parent, title, slug, body=None): self.stdout.write(f" {title} already exists") return SimplePage.objects.get(slug=slug) - page = SimplePageFactory.build( - title=title, slug=slug, body=body or [], show_in_menus=True + page = SimplePageFactory( + parent=parent, + title=title, + slug=slug, + body=body or [], + show_in_menus=True, ) - parent.add_child(instance=page) self.stdout.write(self.style.SUCCESS(f"Created {title}")) return page diff --git a/requirements/dev.in b/requirements/dev.in index 7c25737..309dd5f 100644 --- a/requirements/dev.in +++ b/requirements/dev.in @@ -2,7 +2,7 @@ -c main.txt coverage django-debug-toolbar -factory-boy +wagtail-factories fakeredis isort model_mommy diff --git a/requirements/dev.txt b/requirements/dev.txt index a61a9d2..444a693 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -1,9 +1,17 @@ # This file was autogenerated by uv via the following command: # uv pip compile --output-file requirements/dev.txt requirements/dev.in +anyascii==0.3.3 + # via + # -c requirements/main.txt + # wagtail asgiref==3.11.0 # via # -c requirements/main.txt # django +beautifulsoup4==4.14.3 + # via + # -c requirements/main.txt + # wagtail boolean-py==5.0 # via license-expression cachecontrol==0.14.4 @@ -24,27 +32,88 @@ defusedxml==0.7.1 # via # -c requirements/main.txt # py-serializable + # willow django==6.0.1 # via # -c requirements/main.txt # django-debug-toolbar + # django-filter + # django-modelcluster + # django-permissionedforms + # django-stubs-ext + # django-taggit + # django-tasks + # django-treebeard + # djangorestframework + # laces # model-mommy + # modelsearch + # wagtail django-debug-toolbar==6.1.0 # via -r requirements/dev.in +django-filter==25.2 + # via + # -c requirements/main.txt + # wagtail +django-modelcluster==6.4.1 + # via + # -c requirements/main.txt + # wagtail +django-permissionedforms==0.1 + # via + # -c requirements/main.txt + # wagtail +django-stubs-ext==5.2.8 + # via + # -c requirements/main.txt + # django-tasks +django-taggit==6.1.0 + # via + # -c requirements/main.txt + # wagtail +django-tasks==0.9.0 + # via + # -c requirements/main.txt + # modelsearch + # wagtail +django-treebeard==4.8.0 + # via + # -c requirements/main.txt + # wagtail +djangorestframework==3.16.1 + # via + # -c requirements/main.txt + # wagtail +draftjs-exporter==5.2.0 + # via + # -c requirements/main.txt + # wagtail +et-xmlfile==2.0.0 + # via + # -c requirements/main.txt + # openpyxl factory-boy==3.3.3 - # via -r requirements/dev.in + # via wagtail-factories faker==40.1.0 # via factory-boy fakeredis==2.33.0 # via -r requirements/dev.in filelock==3.20.3 # via cachecontrol +filetype==1.2.0 + # via + # -c requirements/main.txt + # willow idna==3.11 # via # -c requirements/main.txt # requests isort==7.0.0 # via -r requirements/dev.in +laces==0.1.2 + # via + # -c requirements/main.txt + # wagtail license-expression==30.4.4 # via cyclonedx-python-lib markdown-it-py==4.0.0 @@ -53,8 +122,16 @@ mdurl==0.1.2 # via markdown-it-py model-mommy==2.0.0 # via -r requirements/dev.in +modelsearch==1.1.1 + # via + # -c requirements/main.txt + # wagtail msgpack==1.1.2 # via cachecontrol +openpyxl==3.1.5 + # via + # -c requirements/main.txt + # wagtail packageurl-python==0.17.6 # via cyclonedx-python-lib packaging==25.0 @@ -63,6 +140,15 @@ packaging==25.0 # pip-audit # pip-requirements-parser # pipdeptree +pillow==12.1.0 + # via + # -c requirements/main.txt + # pillow-heif + # wagtail +pillow-heif==1.1.1 + # via + # -c requirements/main.txt + # willow pip==25.3 # via # pip-api @@ -92,6 +178,7 @@ requests==2.32.5 # -c requirements/main.txt # cachecontrol # pip-audit + # wagtail rich==14.2.0 # via pip-audit ruff==0.14.11 @@ -100,15 +187,29 @@ sortedcontainers==2.4.0 # via # cyclonedx-python-lib # fakeredis +soupsieve==2.8.1 + # via + # -c requirements/main.txt + # beautifulsoup4 sqlparse==0.5.5 # via # -c requirements/main.txt # django # django-debug-toolbar +telepath==0.3.1 + # via + # -c requirements/main.txt + # wagtail tomli==2.3.0 # via pip-audit tomli-w==1.2.0 # via pip-audit +typing-extensions==4.15.0 + # via + # -c requirements/main.txt + # beautifulsoup4 + # django-stubs-ext + # django-tasks tzdata==2025.3 # via # -c requirements/main.txt @@ -119,3 +220,13 @@ urllib3==2.6.3 # requests uv==0.9.24 # via -r requirements/dev.in +wagtail==7.2.1 + # via + # -c requirements/main.txt + # wagtail-factories +wagtail-factories==4.3.0 + # via -r requirements/dev.in +willow==1.12.0 + # via + # -c requirements/main.txt + # wagtail