diff --git a/config/__init__.py b/config/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/config/asgi.py b/config/asgi.py
new file mode 100644
index 0000000..787b362
--- /dev/null
+++ b/config/asgi.py
@@ -0,0 +1,16 @@
+"""
+ASGI config for config project.
+
+It exposes the ASGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/
+"""
+
+import os
+
+from django.core.asgi import get_asgi_application
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
+
+application = get_asgi_application()
diff --git a/config/settings.py b/config/settings.py
new file mode 100644
index 0000000..bf6ff83
--- /dev/null
+++ b/config/settings.py
@@ -0,0 +1,129 @@
+"""
+Django settings for config project.
+
+Generated by 'django-admin startproject' using Django 4.2.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/4.2/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/4.2/ref/settings/
+"""
+
+from pathlib import Path
+
+# Build paths inside the project like this: BASE_DIR / 'subdir'.
+BASE_DIR = Path(__file__).resolve().parent.parent
+
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = 'django-insecure-o#nbn-&f()kby&qz6+kw8^@r-9(5t-cd!2$(ki086l(d-h2211'
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = True
+
+ALLOWED_HOSTS = []
+
+
+# Application definition
+
+INSTALLED_APPS = [
+ 'django.contrib.admin',
+ 'django.contrib.auth',
+ 'django.contrib.contenttypes',
+ 'django.contrib.sessions',
+ 'django.contrib.messages',
+ 'django.contrib.staticfiles',
+ 'events',
+]
+
+AUTH_USER_MODEL = 'events.User'
+LOGIN_REDIRECT_URL = 'event_list'
+LOGOUT_REDIRECT_URL = 'event_list'
+
+MIDDLEWARE = [
+ 'django.middleware.security.SecurityMiddleware',
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.middleware.common.CommonMiddleware',
+ 'django.middleware.csrf.CsrfViewMiddleware',
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
+ 'django.contrib.messages.middleware.MessageMiddleware',
+ 'django.middleware.clickjacking.XFrameOptionsMiddleware',
+]
+
+ROOT_URLCONF = 'config.urls'
+
+TEMPLATES = [
+ {
+ 'BACKEND': 'django.template.backends.django.DjangoTemplates',
+ 'DIRS': [],
+ 'APP_DIRS': True,
+ 'OPTIONS': {
+ 'context_processors': [
+ 'django.template.context_processors.debug',
+ 'django.template.context_processors.request',
+ 'django.contrib.auth.context_processors.auth',
+ 'django.contrib.messages.context_processors.messages',
+ ],
+ },
+ },
+]
+
+WSGI_APPLICATION = 'config.wsgi.application'
+
+
+# Database
+# https://docs.djangoproject.com/en/4.2/ref/settings/#databases
+
+DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.sqlite3',
+ 'NAME': BASE_DIR / 'db.sqlite3',
+ }
+}
+
+
+# Password validation
+# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators
+
+AUTH_PASSWORD_VALIDATORS = [
+ {
+ 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
+ },
+]
+
+
+# Internationalization
+# https://docs.djangoproject.com/en/4.2/topics/i18n/
+
+LANGUAGE_CODE = 'en-us'
+
+TIME_ZONE = 'UTC'
+
+USE_I18N = True
+
+USE_TZ = True
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/4.2/howto/static-files/
+
+STATIC_URL = 'static/'
+
+# Default primary key field type
+# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
+
+DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
+
diff --git a/config/urls.py b/config/urls.py
new file mode 100644
index 0000000..09199ad
--- /dev/null
+++ b/config/urls.py
@@ -0,0 +1,26 @@
+"""
+URL configuration for config project.
+
+The `urlpatterns` list routes URLs to views. For more information please see:
+ https://docs.djangoproject.com/en/4.2/topics/http/urls/
+Examples:
+Function views
+ 1. Add an import: from my_app import views
+ 2. Add a URL to urlpatterns: path('', views.home, name='home')
+Class-based views
+ 1. Add an import: from other_app.views import Home
+ 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
+Including another URLconf
+ 1. Import the include() function: from django.urls import include, path
+ 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
+"""
+from django.contrib import admin
+from django.urls import path, include
+from events import views
+
+urlpatterns = [
+ path('admin/', admin.site.urls),
+ path('', views.event_list, name='event_list'),
+ path('events/', include('events.urls')),
+ path('accounts/', include('django.contrib.auth.urls')),
+]
diff --git a/config/wsgi.py b/config/wsgi.py
new file mode 100644
index 0000000..8ae71e3
--- /dev/null
+++ b/config/wsgi.py
@@ -0,0 +1,16 @@
+"""
+WSGI config for config project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
+
+application = get_wsgi_application()
diff --git a/events/__init__.py b/events/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/events/admin.py b/events/admin.py
new file mode 100644
index 0000000..8c38f3f
--- /dev/null
+++ b/events/admin.py
@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.
diff --git a/events/apps.py b/events/apps.py
new file mode 100644
index 0000000..20f48f2
--- /dev/null
+++ b/events/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class EventsConfig(AppConfig):
+ default_auto_field = 'django.db.models.BigAutoField'
+ name = 'events'
diff --git a/events/forms.py b/events/forms.py
new file mode 100644
index 0000000..3a23231
--- /dev/null
+++ b/events/forms.py
@@ -0,0 +1,25 @@
+from django import forms
+from .models import Event, User
+
+class EventForm(forms.ModelForm):
+ class Meta:
+ model = Event
+ fields = ['name', 'description', 'event_date']
+ widgets = {
+ 'event_date': forms.DateTimeInput(attrs={'type': 'datetime-local'}),
+ }
+
+class UserRegistrationForm(forms.ModelForm):
+ password = forms.CharField(widget=forms.PasswordInput)
+ password_confirmation = forms.CharField(widget=forms.PasswordInput)
+
+ class Meta:
+ model = User
+ fields = ['display_name', 'email', 'username']
+
+ def clean(self):
+ cleaned_data = super().clean()
+ if cleaned_data.get('password') != cleaned_data.get('password_confirmation'):
+ raise forms.ValidationError('パスワードが一致しません')
+ return cleaned_data
+
diff --git a/events/migrations/0001_initial.py b/events/migrations/0001_initial.py
new file mode 100644
index 0000000..fbb7463
--- /dev/null
+++ b/events/migrations/0001_initial.py
@@ -0,0 +1,75 @@
+# Generated by Django 4.2 on 2025-01-17 15:14
+
+from django.conf import settings
+import django.contrib.auth.models
+import django.contrib.auth.validators
+from django.db import migrations, models
+import django.db.models.deletion
+import django.utils.timezone
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ('auth', '0012_alter_user_first_name_max_length'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='User',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('password', models.CharField(max_length=128, verbose_name='password')),
+ ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
+ ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
+ ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
+ ('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
+ ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
+ ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
+ ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
+ ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
+ ('display_name', models.CharField(max_length=100)),
+ ('email', models.EmailField(max_length=254, unique=True)),
+ ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
+ ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
+ ],
+ options={
+ 'verbose_name': 'user',
+ 'verbose_name_plural': 'users',
+ 'abstract': False,
+ },
+ managers=[
+ ('objects', django.contrib.auth.models.UserManager()),
+ ],
+ ),
+ migrations.CreateModel(
+ name='Event',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=200)),
+ ('description', models.TextField()),
+ ('event_date', models.DateTimeField()),
+ ('created_at', models.DateTimeField(default=django.utils.timezone.now)),
+ ('organizer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='organized_events', to=settings.AUTH_USER_MODEL)),
+ ],
+ ),
+ migrations.CreateModel(
+ name='EventParticipation',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('registered_at', models.DateTimeField(default=django.utils.timezone.now)),
+ ('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='events.event')),
+ ('participant', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
+ ],
+ options={
+ 'unique_together': {('event', 'participant')},
+ },
+ ),
+ migrations.AddField(
+ model_name='event',
+ name='participants',
+ field=models.ManyToManyField(related_name='participating_events', through='events.EventParticipation', to=settings.AUTH_USER_MODEL),
+ ),
+ ]
diff --git a/events/migrations/__init__.py b/events/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/events/models.py b/events/models.py
new file mode 100644
index 0000000..7a092e2
--- /dev/null
+++ b/events/models.py
@@ -0,0 +1,30 @@
+from django.db import models
+from django.contrib.auth.models import AbstractUser
+from django.utils import timezone
+
+class User(AbstractUser):
+ display_name = models.CharField(max_length=100)
+ email = models.EmailField(unique=True)
+
+ def __str__(self):
+ return self.display_name
+
+class Event(models.Model):
+ name = models.CharField(max_length=200)
+ description = models.TextField()
+ organizer = models.ForeignKey(User, on_delete=models.CASCADE, related_name='organized_events')
+ event_date = models.DateTimeField()
+ created_at = models.DateTimeField(default=timezone.now)
+ participants = models.ManyToManyField(User, through='EventParticipation', related_name='participating_events')
+
+ def __str__(self):
+ return self.name
+
+class EventParticipation(models.Model):
+ event = models.ForeignKey(Event, on_delete=models.CASCADE)
+ participant = models.ForeignKey(User, on_delete=models.CASCADE)
+ registered_at = models.DateTimeField(default=timezone.now)
+
+ class Meta:
+ unique_together = ('event', 'participant')
+
diff --git a/events/templates/events/base.html b/events/templates/events/base.html
new file mode 100644
index 0000000..37e278b
--- /dev/null
+++ b/events/templates/events/base.html
@@ -0,0 +1,41 @@
+
+
+
+
+ {% block title %}イベント管理システム{% endblock %}
+
+
+
+
+
+
+ {% if messages %}
+ {% for message in messages %}
+
+ {{ message }}
+
+ {% endfor %}
+ {% endif %}
+
+ {% block content %}
+ {% endblock %}
+
+
+
+
+
+
diff --git a/events/templates/events/event_detail.html b/events/templates/events/event_detail.html
new file mode 100644
index 0000000..7b28bdf
--- /dev/null
+++ b/events/templates/events/event_detail.html
@@ -0,0 +1,33 @@
+
+{% extends 'events/base.html' %}
+
+{% block title %}{{ event.name }}{% endblock %}
+
+{% block content %}
+
+
+
{{ event.name }}
+
{{ event.description }}
+
+ 主催者: {{ event.organizer.display_name }}
+ 開催日時: {{ event.event_date }}
+ 作成日時: {{ event.created_at }}
+
+
+ {% if user.is_authenticated and not is_participant %}
+
+ {% endif %}
+
+
参加者一覧
+
+ {% for participant in participants %}
+ - {{ participant.display_name }}
+ {% endfor %}
+
+
+
+{% endblock %}
+
diff --git a/events/templates/events/event_form.html b/events/templates/events/event_form.html
new file mode 100644
index 0000000..5b75791
--- /dev/null
+++ b/events/templates/events/event_form.html
@@ -0,0 +1,25 @@
+
+{% extends 'events/base.html' %}
+
+{% block title %}イベント作成{% endblock %}
+
+{% block content %}
+イベント作成
+
+{% endblock %}
+
diff --git a/events/templates/events/event_list.html b/events/templates/events/event_list.html
new file mode 100644
index 0000000..f397d84
--- /dev/null
+++ b/events/templates/events/event_list.html
@@ -0,0 +1,28 @@
+
+{% extends 'events/base.html' %}
+
+{% block title %}イベント一覧{% endblock %}
+
+{% block content %}
+イベント一覧
+
+ {% for event in events %}
+
+
+
+
{{ event.name }}
+
{{ event.description|truncatewords:30 }}
+
+
+ 主催者: {{ event.organizer.display_name }}
+ 開催日時: {{ event.event_date }}
+
+
+
詳細を見る
+
+
+
+ {% endfor %}
+
+{% endblock %}
+
diff --git a/events/templates/events/user_register.html b/events/templates/events/user_register.html
new file mode 100644
index 0000000..3c8ed43
--- /dev/null
+++ b/events/templates/events/user_register.html
@@ -0,0 +1,33 @@
+
+{% extends 'events/base.html' %}
+
+{% block title %}ユーザー登録{% endblock %}
+
+{% block content %}
+ユーザー登録
+
+{% endblock %}
+
diff --git a/events/templates/registration/login.html b/events/templates/registration/login.html
new file mode 100644
index 0000000..97ef482
--- /dev/null
+++ b/events/templates/registration/login.html
@@ -0,0 +1,24 @@
+
+{% extends 'events/base.html' %}
+
+{% block title %}ログイン{% endblock %}
+
+{% block content %}
+ログイン
+
+
+ アカウントをお持ちでない方はこちらから登録してください。
+
+{% endblock %}
+
diff --git a/events/tests.py b/events/tests.py
new file mode 100644
index 0000000..7ce503c
--- /dev/null
+++ b/events/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/events/urls.py b/events/urls.py
new file mode 100644
index 0000000..4c00cfe
--- /dev/null
+++ b/events/urls.py
@@ -0,0 +1,10 @@
+from django.urls import path
+from . import views
+
+urlpatterns = [
+ path('create/', views.event_create, name='event_create'),
+ path('/', views.event_detail, name='event_detail'),
+ path('/participate/', views.event_participate, name='event_participate'),
+ path('register/', views.user_register, name='user_register'),
+]
+
diff --git a/events/views.py b/events/views.py
new file mode 100644
index 0000000..57ad2b9
--- /dev/null
+++ b/events/views.py
@@ -0,0 +1,54 @@
+from django.shortcuts import render, redirect, get_object_or_404
+from django.contrib.auth.decorators import login_required
+from django.contrib import messages
+from .models import Event, EventParticipation
+from .forms import EventForm, UserRegistrationForm
+
+def event_list(request):
+ events = Event.objects.all().order_by('-event_date')
+ return render(request, 'events/event_list.html', {'events': events})
+
+@login_required
+def event_create(request):
+ if request.method == 'POST':
+ form = EventForm(request.POST)
+ if form.is_valid():
+ event = form.save(commit=False)
+ event.organizer = request.user
+ event.save()
+ return redirect('event_detail', event_id=event.id)
+ else:
+ form = EventForm()
+ return render(request, 'events/event_form.html', {'form': form})
+
+def event_detail(request, event_id):
+ event = get_object_or_404(Event, id=event_id)
+ participants = event.participants.all()
+ is_participant = request.user.is_authenticated and event.participants.filter(id=request.user.id).exists()
+ return render(request, 'events/event_detail.html', {
+ 'event': event,
+ 'participants': participants,
+ 'is_participant': is_participant
+ })
+
+@login_required
+def event_participate(request, event_id):
+ event = get_object_or_404(Event, id=event_id)
+ if not EventParticipation.objects.filter(event=event, participant=request.user).exists():
+ EventParticipation.objects.create(event=event, participant=request.user)
+ messages.success(request, 'イベントへの参加が完了しました')
+ return redirect('event_detail', event_id=event.id)
+
+def user_register(request):
+ if request.method == 'POST':
+ form = UserRegistrationForm(request.POST)
+ if form.is_valid():
+ user = form.save(commit=False)
+ user.set_password(form.cleaned_data['password'])
+ user.save()
+ messages.success(request, 'ユーザー登録が完了しました')
+ return redirect('login')
+ else:
+ form = UserRegistrationForm()
+ return render(request, 'events/user_register.html', {'form': form})
+
diff --git a/hello.py b/hello.py
new file mode 100644
index 0000000..21b6854
--- /dev/null
+++ b/hello.py
@@ -0,0 +1,6 @@
+def main():
+ print("Hello from pyhack!")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/hello/__init__.py b/hello/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/hello/admin.py b/hello/admin.py
new file mode 100644
index 0000000..8c38f3f
--- /dev/null
+++ b/hello/admin.py
@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.
diff --git a/hello/apps.py b/hello/apps.py
new file mode 100644
index 0000000..bfc55f0
--- /dev/null
+++ b/hello/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class HelloConfig(AppConfig):
+ default_auto_field = 'django.db.models.BigAutoField'
+ name = 'hello'
diff --git a/hello/migrations/__init__.py b/hello/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/hello/models.py b/hello/models.py
new file mode 100644
index 0000000..71a8362
--- /dev/null
+++ b/hello/models.py
@@ -0,0 +1,3 @@
+from django.db import models
+
+# Create your models here.
diff --git a/hello/templates/hello/index.html b/hello/templates/hello/index.html
new file mode 100644
index 0000000..2bc8e3b
--- /dev/null
+++ b/hello/templates/hello/index.html
@@ -0,0 +1,10 @@
+
+
+
+ Hello World
+
+
+ Hello World
+
+
+
diff --git a/hello/tests.py b/hello/tests.py
new file mode 100644
index 0000000..7ce503c
--- /dev/null
+++ b/hello/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/hello/urls.py b/hello/urls.py
new file mode 100644
index 0000000..19c1fd1
--- /dev/null
+++ b/hello/urls.py
@@ -0,0 +1,8 @@
+from django.urls import path
+from . import views
+
+app_name = 'hello'
+urlpatterns = [
+ path('', views.index, name='index'),
+]
+
diff --git a/hello/views.py b/hello/views.py
new file mode 100644
index 0000000..3aa4536
--- /dev/null
+++ b/hello/views.py
@@ -0,0 +1,4 @@
+from django.shortcuts import render
+
+def index(request):
+ return render(request, 'hello/index.html')
diff --git a/manage.py b/manage.py
new file mode 100755
index 0000000..8e7ac79
--- /dev/null
+++ b/manage.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+"""Django's command-line utility for administrative tasks."""
+import os
+import sys
+
+
+def main():
+ """Run administrative tasks."""
+ os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
+ try:
+ from django.core.management import execute_from_command_line
+ except ImportError as exc:
+ raise ImportError(
+ "Couldn't import Django. Are you sure it's installed and "
+ "available on your PYTHONPATH environment variable? Did you "
+ "forget to activate a virtual environment?"
+ ) from exc
+ execute_from_command_line(sys.argv)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/pyproject.toml b/pyproject.toml
index d074d89..78876d5 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -5,5 +5,9 @@ description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
- "django>=5.1.5",
+ "django==4.2",
+ "django-ninja>=1.3.0",
]
+
+[tool.uv.workspace]
+members = ["pyhack"]
diff --git a/uv.lock b/uv.lock
index 130c4c0..26d3587 100644
--- a/uv.lock
+++ b/uv.lock
@@ -1,6 +1,21 @@
version = 1
requires-python = ">=3.12"
+[manifest]
+members = [
+ "demo-ai-django-pyhack",
+ "pyhack",
+]
+
+[[package]]
+name = "annotated-types"
+version = "0.7.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 },
+]
+
[[package]]
name = "asgiref"
version = "3.8.1"
@@ -16,25 +31,100 @@ version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "django" },
+ { name = "django-ninja" },
]
[package.metadata]
-requires-dist = [{ name = "django", specifier = ">=5.1.5" }]
+requires-dist = [
+ { name = "django", specifier = "==4.2" },
+ { name = "django-ninja", specifier = ">=1.3.0" },
+]
[[package]]
name = "django"
-version = "5.1.5"
+version = "4.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "asgiref" },
{ name = "sqlparse" },
{ name = "tzdata", marker = "sys_platform == 'win32'" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/e4/17/834e3e08d590dcc27d4cc3c5cd4e2fb757b7a92bab9de8ee402455732952/Django-5.1.5.tar.gz", hash = "sha256:19bbca786df50b9eca23cee79d495facf55c8f5c54c529d9bf1fe7b5ea086af3", size = 10700031 }
+sdist = { url = "https://files.pythonhosted.org/packages/9a/bb/48aa3e0850923096dff2766d21a6004d6e1a3317f0bd400ba81f586754e1/Django-4.2.tar.gz", hash = "sha256:c36e2ab12824e2ac36afa8b2515a70c53c7742f0d6eaefa7311ec379558db997", size = 10415665 }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d9/40/6012f98b14b64b4d3dc47b0c2f116fccbd0795ab35515d0c40dac73b81b8/Django-4.2-py3-none-any.whl", hash = "sha256:ad33ed68db9398f5dfb33282704925bce044bef4261cd4fb59e4e7f9ae505a78", size = 7988617 },
+]
+
+[[package]]
+name = "django-ninja"
+version = "1.3.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "django" },
+ { name = "pydantic" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/9c/77/89ee4ebaa5151b7d85cebaf8d6ec0b9e5074326c3ad8259c763763306d51/django_ninja-1.3.0.tar.gz", hash = "sha256:5b320e2dc0f41a6032bfa7e1ebc33559ae1e911a426f0c6be6674a50b20819be", size = 3702324 }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/00/72/fd2589323b40893d3224e174eeec0c4ce5a42c7d2d384d11ba269ad4d050/django_ninja-1.3.0-py3-none-any.whl", hash = "sha256:f58096b6c767d1403dfd6c49743f82d780d7b9688d9302ecab316ac1fa6131bb", size = 2423381 },
+]
+
+[[package]]
+name = "pydantic"
+version = "2.10.5"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "annotated-types" },
+ { name = "pydantic-core" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/6a/c7/ca334c2ef6f2e046b1144fe4bb2a5da8a4c574e7f2ebf7e16b34a6a2fa92/pydantic-2.10.5.tar.gz", hash = "sha256:278b38dbbaec562011d659ee05f63346951b3a248a6f3642e1bc68894ea2b4ff", size = 761287 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/11/e6/e92c8c788b83d109f34d933c5e817095d85722719cb4483472abc135f44e/Django-5.1.5-py3-none-any.whl", hash = "sha256:c46eb936111fffe6ec4bc9930035524a8be98ec2f74d8a0ff351226a3e52f459", size = 8276957 },
+ { url = "https://files.pythonhosted.org/packages/58/26/82663c79010b28eddf29dcdd0ea723439535fa917fce5905885c0e9ba562/pydantic-2.10.5-py3-none-any.whl", hash = "sha256:4dd4e322dbe55472cb7ca7e73f4b63574eecccf2835ffa2af9021ce113c83c53", size = 431426 },
]
+[[package]]
+name = "pydantic-core"
+version = "2.27.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/fc/01/f3e5ac5e7c25833db5eb555f7b7ab24cd6f8c322d3a3ad2d67a952dc0abc/pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39", size = 413443 }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d6/74/51c8a5482ca447871c93e142d9d4a92ead74de6c8dc5e66733e22c9bba89/pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0", size = 1893127 },
+ { url = "https://files.pythonhosted.org/packages/d3/f3/c97e80721735868313c58b89d2de85fa80fe8dfeeed84dc51598b92a135e/pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef", size = 1811340 },
+ { url = "https://files.pythonhosted.org/packages/9e/91/840ec1375e686dbae1bd80a9e46c26a1e0083e1186abc610efa3d9a36180/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7", size = 1822900 },
+ { url = "https://files.pythonhosted.org/packages/f6/31/4240bc96025035500c18adc149aa6ffdf1a0062a4b525c932065ceb4d868/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934", size = 1869177 },
+ { url = "https://files.pythonhosted.org/packages/fa/20/02fbaadb7808be578317015c462655c317a77a7c8f0ef274bc016a784c54/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6", size = 2038046 },
+ { url = "https://files.pythonhosted.org/packages/06/86/7f306b904e6c9eccf0668248b3f272090e49c275bc488a7b88b0823444a4/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c", size = 2685386 },
+ { url = "https://files.pythonhosted.org/packages/8d/f0/49129b27c43396581a635d8710dae54a791b17dfc50c70164866bbf865e3/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2", size = 1997060 },
+ { url = "https://files.pythonhosted.org/packages/0d/0f/943b4af7cd416c477fd40b187036c4f89b416a33d3cc0ab7b82708a667aa/pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4", size = 2004870 },
+ { url = "https://files.pythonhosted.org/packages/35/40/aea70b5b1a63911c53a4c8117c0a828d6790483f858041f47bab0b779f44/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3", size = 1999822 },
+ { url = "https://files.pythonhosted.org/packages/f2/b3/807b94fd337d58effc5498fd1a7a4d9d59af4133e83e32ae39a96fddec9d/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4", size = 2130364 },
+ { url = "https://files.pythonhosted.org/packages/fc/df/791c827cd4ee6efd59248dca9369fb35e80a9484462c33c6649a8d02b565/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57", size = 2158303 },
+ { url = "https://files.pythonhosted.org/packages/9b/67/4e197c300976af185b7cef4c02203e175fb127e414125916bf1128b639a9/pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc", size = 1834064 },
+ { url = "https://files.pythonhosted.org/packages/1f/ea/cd7209a889163b8dcca139fe32b9687dd05249161a3edda62860430457a5/pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9", size = 1989046 },
+ { url = "https://files.pythonhosted.org/packages/bc/49/c54baab2f4658c26ac633d798dab66b4c3a9bbf47cff5284e9c182f4137a/pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b", size = 1885092 },
+ { url = "https://files.pythonhosted.org/packages/41/b1/9bc383f48f8002f99104e3acff6cba1231b29ef76cfa45d1506a5cad1f84/pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b", size = 1892709 },
+ { url = "https://files.pythonhosted.org/packages/10/6c/e62b8657b834f3eb2961b49ec8e301eb99946245e70bf42c8817350cbefc/pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154", size = 1811273 },
+ { url = "https://files.pythonhosted.org/packages/ba/15/52cfe49c8c986e081b863b102d6b859d9defc63446b642ccbbb3742bf371/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9", size = 1823027 },
+ { url = "https://files.pythonhosted.org/packages/b1/1c/b6f402cfc18ec0024120602bdbcebc7bdd5b856528c013bd4d13865ca473/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9", size = 1868888 },
+ { url = "https://files.pythonhosted.org/packages/bd/7b/8cb75b66ac37bc2975a3b7de99f3c6f355fcc4d89820b61dffa8f1e81677/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1", size = 2037738 },
+ { url = "https://files.pythonhosted.org/packages/c8/f1/786d8fe78970a06f61df22cba58e365ce304bf9b9f46cc71c8c424e0c334/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a", size = 2685138 },
+ { url = "https://files.pythonhosted.org/packages/a6/74/d12b2cd841d8724dc8ffb13fc5cef86566a53ed358103150209ecd5d1999/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e", size = 1997025 },
+ { url = "https://files.pythonhosted.org/packages/a0/6e/940bcd631bc4d9a06c9539b51f070b66e8f370ed0933f392db6ff350d873/pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4", size = 2004633 },
+ { url = "https://files.pythonhosted.org/packages/50/cc/a46b34f1708d82498c227d5d80ce615b2dd502ddcfd8376fc14a36655af1/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27", size = 1999404 },
+ { url = "https://files.pythonhosted.org/packages/ca/2d/c365cfa930ed23bc58c41463bae347d1005537dc8db79e998af8ba28d35e/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee", size = 2130130 },
+ { url = "https://files.pythonhosted.org/packages/f4/d7/eb64d015c350b7cdb371145b54d96c919d4db516817f31cd1c650cae3b21/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1", size = 2157946 },
+ { url = "https://files.pythonhosted.org/packages/a4/99/bddde3ddde76c03b65dfd5a66ab436c4e58ffc42927d4ff1198ffbf96f5f/pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130", size = 1834387 },
+ { url = "https://files.pythonhosted.org/packages/71/47/82b5e846e01b26ac6f1893d3c5f9f3a2eb6ba79be26eef0b759b4fe72946/pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee", size = 1990453 },
+ { url = "https://files.pythonhosted.org/packages/51/b2/b2b50d5ecf21acf870190ae5d093602d95f66c9c31f9d5de6062eb329ad1/pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b", size = 1885186 },
+]
+
+[[package]]
+name = "pyhack"
+version = "0.1.0"
+source = { virtual = "pyhack" }
+
[[package]]
name = "sqlparse"
version = "0.5.3"
@@ -44,6 +134,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/a9/5c/bfd6bd0bf979426d405cc6e71eceb8701b148b16c21d2dc3c261efc61c7b/sqlparse-0.5.3-py3-none-any.whl", hash = "sha256:cf2196ed3418f3ba5de6af7e82c694a9fbdbfecccdfc72e281548517081f16ca", size = 44415 },
]
+[[package]]
+name = "typing-extensions"
+version = "4.12.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 },
+]
+
[[package]]
name = "tzdata"
version = "2024.2"