11 Commits

Author SHA1 Message Date
8aa8eda6ce Tweaks 2024-05-23 06:54:48 +02:00
2d56d06649 Dockerize 2024-05-18 19:19:16 +02:00
382e514d03 City as select 2024-05-16 21:40:28 +02:00
fc6b3a7fa0 Validation 2024-05-16 07:55:27 +02:00
2fc2d07a7d Persons constraint 2024-05-16 07:35:01 +02:00
178377cfb6 Finished 2024-05-15 22:56:30 +02:00
af61d45fa4 Basic table inline edit functionality 2024-05-15 22:16:59 +02:00
7c20d4d23e BS icons 2024-05-15 21:56:28 +02:00
4ca502c6bc Finish filter list 2024-05-15 17:25:58 +02:00
4c7b18d07b Filter list with db model 2024-05-14 22:34:21 +02:00
1456ba8538 Cat breeds 2024-04-16 15:23:08 +02:00
36 changed files with 8320 additions and 7294 deletions

1
.dockerignore Normal file
View File

@ -0,0 +1 @@
**/*.pyc

2
.gitignore vendored
View File

@ -2,5 +2,5 @@
/.vscode
/.venv
__pycache__
/db.sqlite3
/project/settings_local.py
/db.sqlite3

51
Dockerfile Normal file
View File

@ -0,0 +1,51 @@
FROM python:3.11-slim-bookworm AS env-builder
WORKDIR /app
COPY pyproject.toml .
COPY poetry.lock .
# create virtual environment
RUN python -m venv /venv
# set python thingies, set environment variables and activate virtual environment
ENV \
PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PATH="/venv/bin:$PATH"
RUN \
pip install poetry && \
# dump python dependencies into requirements file
poetry export --without-hashes --format=requirements.txt > requirements.txt && \
# install python libs
pip install -r requirements.txt --no-cache-dir --prefer-binary --no-deps --no-compile
FROM python:3.11-slim-bookworm
WORKDIR /app
COPY --from=env-builder /venv /venv
# set python thingies and activate virtual environment
ENV \
PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PATH="/venv/bin:$PATH"
COPY manage.py .
COPY pyproject.toml .
COPY poetry.lock .
COPY db.template.sqlite3 db.sqlite3
COPY ./project ./project
# run as user www-data
USER 33
ENTRYPOINT [ "/venv/bin/gunicorn" ]
CMD [ \
"--bind", "0.0.0.0:8000", \
"--workers", "4", \
"project.wsgi" \
]

View File

@ -1,3 +1,7 @@
CONTAINER_NAME=django-htmx
IMAGE_NAME=django-htmx
ifeq ($(VIRTUAL_ENV),)
RUN_IN_ENV=poetry run
else
@ -19,3 +23,20 @@ migrations:
migrate:
@ $(RUN_IN_ENV) python manage.py migrate
docker-build:
- @docker image rm $(IMAGE_NAME) --force
@docker \
build . \
-t $(IMAGE_NAME)
@docker \
build . \
-t $(IMAGE_NAME)
docker-run:
@docker run \
--publish 8000:8000 \
--name $(CONTAINER_NAME) \
$(IMAGE_NAME)

View File

@ -1 +1,36 @@
# Django-htmx demo
## Run demo
### As docker container
```
make docker-build
make docker-run
```
Browse to [localhost:8000](http://localhost:8000).
Later, start and stop docker container using:
```
docker start django-htmx
```
and
```
docker stop django-htmx
```
### As standard local Django app
- requirements: Python 3.10 or 3.11
- [poetry](https://python-poetry.org)
```
poetry install
make run
```
Browse to [localhost:8000](http://localhost:8000).

BIN
db.template.sqlite3 Normal file

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

27
poetry.lock generated
View File

@ -19,13 +19,13 @@ tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"]
[[package]]
name = "django"
version = "5.0.4"
version = "5.0.6"
description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design."
optional = false
python-versions = ">=3.10"
files = [
{file = "Django-5.0.4-py3-none-any.whl", hash = "sha256:916423499d75d62da7aa038d19aef23d23498d8df229775eb0a6309ee1013775"},
{file = "Django-5.0.4.tar.gz", hash = "sha256:4bd01a8c830bb77a8a3b0e7d8b25b887e536ad17a81ba2dce5476135c73312bd"},
{file = "Django-5.0.6-py3-none-any.whl", hash = "sha256:8363ac062bb4ef7c3f12d078f6fa5d154031d129a15170a1066412af49d30905"},
{file = "Django-5.0.6.tar.gz", hash = "sha256:ff1b61005004e476e0aeea47c7f79b85864c70124030e95146315396f1e7951f"},
]
[package.dependencies]
@ -74,13 +74,13 @@ tornado = ["tornado (>=0.2)"]
[[package]]
name = "jinja2"
version = "3.1.3"
version = "3.1.4"
description = "A very fast and expressive template engine."
optional = false
python-versions = ">=3.7"
files = [
{file = "Jinja2-3.1.3-py3-none-any.whl", hash = "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa"},
{file = "Jinja2-3.1.3.tar.gz", hash = "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90"},
{file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"},
{file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"},
]
[package.dependencies]
@ -171,19 +171,18 @@ files = [
[[package]]
name = "sqlparse"
version = "0.4.4"
version = "0.5.0"
description = "A non-validating SQL parser."
optional = false
python-versions = ">=3.5"
python-versions = ">=3.8"
files = [
{file = "sqlparse-0.4.4-py3-none-any.whl", hash = "sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3"},
{file = "sqlparse-0.4.4.tar.gz", hash = "sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c"},
{file = "sqlparse-0.5.0-py3-none-any.whl", hash = "sha256:c204494cd97479d0e39f28c93d46c0b2d5959c7b9ab904762ea6c7af211c8663"},
{file = "sqlparse-0.5.0.tar.gz", hash = "sha256:714d0a4932c059d16189f58ef5411ec2287a4360f17cdd0edd2d09d4c5087c93"},
]
[package.extras]
dev = ["build", "flake8"]
dev = ["build", "hatch"]
doc = ["sphinx"]
test = ["pytest", "pytest-cov"]
[[package]]
name = "typing-extensions"
@ -209,5 +208,5 @@ files = [
[metadata]
lock-version = "2.0"
python-versions = "^3.10"
content-hash = "6c86d5721314c92afa919983780e664a1573ebb7c25a8b54622393b97990e509"
python-versions = ">= 3.10, < 3.12"
content-hash = "26984438b0e835c052014186db2a76cbe044e19fd5b56ba3fc3d642b2ed530dc"

View File

@ -1,6 +1,21 @@
import os
import shutil
from django.apps import AppConfig
from django.conf import settings
class MainConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "project.main"
def ready(self):
"""copy template database if db not exists"""
db_fname = settings.DATABASES["default"]["NAME"]
template_db_fname = settings.BASE_DIR / "db.template.sqlite3"
if os.path.exists(db_fname):
return
shutil.copyfile(template_db_fname, db_fname)

View File

@ -1,6 +1,5 @@
# Generated by Django 5.0.4 on 2024-04-10 19:31
# Generated by Django 5.0.4 on 2024-05-14 20:16
import django.db.models.deletion
from django.db import migrations, models
@ -11,7 +10,7 @@ class Migration(migrations.Migration):
operations = [
migrations.CreateModel(
name="County",
name="CatBreed",
fields=[
(
"id",
@ -23,62 +22,13 @@ class Migration(migrations.Migration):
),
),
("name", models.CharField(max_length=100)),
("country", models.CharField(max_length=100)),
("origin", models.CharField(max_length=100)),
("coat", models.CharField(max_length=100)),
("pattern", models.CharField(max_length=100)),
],
options={
"db_table": "counties",
"ordering": ["name"],
},
),
migrations.CreateModel(
name="PostOffice",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("zip", models.PositiveIntegerField()),
("name", models.CharField(max_length=100)),
],
options={
"db_table": "post_offices",
"ordering": ["zip"],
},
),
migrations.CreateModel(
name="Area",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=100)),
(
"county",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="main.county"
),
),
(
"post_office",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="main.postoffice",
),
),
],
options={
"db_table": "areas",
"ordering": ["name"],
"db_table": "cat_breeds",
},
),
]

View File

@ -1,48 +0,0 @@
# Generated by Django 5.0.4 on 2024-04-10 19:42
from django.db import migrations
counties = [
'KoprivničkO-križevačka',
'Međimurska',
'Dubrovačko-neretvanska',
'Zagrebačka',
'Primorsko-goranska',
'Požeško-slavonska',
'Vukovarsko-srijemska',
'Karlovačka',
'Zadarska',
'Bjelovarsko-bilogorska',
'Splitsko-dalmatinska',
'Virovitičko-podravska',
'Ličko-senjska',
'Grad Zagreb',
'Brodsko-posavska',
'Osječko-baranjska',
'Sisačko-moslavačka',
'Krapinsko-zagorska',
'Istarska',
'Šibensko-kninska',
'Varaždinska',
]
def create_counties(apps, schema_editor):
County = apps.get_model("main", "County")
bulk = []
for county in counties:
bulk.append(County(name=county))
County.objects.bulk_create(bulk)
class Migration(migrations.Migration):
dependencies = [
("main", "0001_initial"),
]
operations = [
migrations.RunPython(create_counties),
]

View File

@ -0,0 +1,717 @@
from dataclasses import dataclass
from django.db import migrations
@dataclass
class Breed:
name: str
country: str
origin: str
coat: str
pattern: str
cat_breeds = [
Breed(
name="Abyssinian",
country="Ethiopia",
origin="Natural/Standard",
coat="Short",
pattern="Ticked",
),
Breed(
name="Aegean",
country="Greece",
origin="Natural/Standard",
coat="Semi-long",
pattern="Bi- or tri-colored",
),
Breed(
name="American Curl",
country="United States",
origin="Mutation",
coat="Short/Long",
pattern="All",
),
Breed(
name="American Bobtail",
country="United States",
origin="Mutation",
coat="Short/Long",
pattern="All",
),
Breed(
name="American Shorthair",
country="United States",
origin="Natural",
coat="Short",
pattern="All but colorpoint",
),
Breed(
name="American Wirehair",
country="United States",
origin="Mutation",
coat="Rex",
pattern="All but colorpoint",
),
Breed(
name="Arabian Mau",
country="Arabian Peninsula",
origin="Natural",
coat="Short",
pattern="",
),
Breed(
name="Australian Mist",
country="Australia",
origin="Crossbreed",
coat="Short",
pattern="Spotted and Classic tabby",
),
Breed(
name="Asian",
country="United Kingdom",
origin="",
coat="Short",
pattern="Evenly solid",
),
Breed(
name="Asian Semi-longhair",
country="United Kingdom",
origin="Crossbreed",
coat="Semi-long",
pattern="Solid",
),
Breed(
name="Balinese",
country="United States",
origin="Crossbreed",
coat="Long",
pattern="Colorpoint",
),
Breed(
name="Bambino",
country="United States",
origin="Crossbreed",
coat="Hairless/Furry down",
pattern="",
),
Breed(
name="Bengal",
country="United States",
origin="Hybrid",
coat="Short",
pattern="Spotted/Marbled",
),
Breed(
name="Birman",
country="France",
origin="Natural",
coat="Semi Long",
pattern="Colorpoint",
),
Breed(
name="Bombay",
country="United States",
origin="Crossbred",
coat="Short",
pattern="Solid",
),
Breed(
name="Brazilian Shorthair",
country="Brazil",
origin="Natural",
coat="Short",
pattern="All",
),
Breed(
name="British Semi-longhair",
country="United Kingdom",
origin="",
coat="Medium",
pattern="All",
),
Breed(
name="British Shorthair",
country="United Kingdom",
origin="Natural",
coat="Short",
pattern="All",
),
Breed(
name="British Longhair",
country="United Kingdom",
origin="",
coat="Long",
pattern="",
),
Breed(
name="Burmese",
country="Burma and Thailand",
origin="Natural",
coat="Short",
pattern="Solid",
),
Breed(
name="Burmilla",
country="United Kingdom",
origin="Crossbreed",
coat="Short/Long",
pattern="",
),
Breed(
name="California Spangled",
country="United States",
origin="Crossbreed",
coat="Short",
pattern="Spotted",
),
Breed(
name="Chantilly-Tiffany",
country="United States",
origin="",
coat="",
pattern="",
),
Breed(
name="Chartreux",
country="France",
origin="Natural",
coat="Short",
pattern="Solid",
),
Breed(
name="Chausie",
country="France",
origin="Hybrid",
coat="Short",
pattern="Ticked",
),
Breed(
name="Cheetoh",
country="United States",
origin="Hybrid Crossbreed",
coat="Short",
pattern="Spotted",
),
Breed(
name="Cornish Rex",
country="United Kingdom",
origin="Mutation",
coat="Rex",
pattern="All",
),
Breed(
name="Cymric or Manx Longhair",
country="United Kingdom",
origin="Natural/Mutation",
coat="Long",
pattern="",
),
Breed(
name="Cyprus",
country="Cyprus",
origin="Natural",
coat="All",
pattern="All",
),
Breed(
name="Devon Rex",
country="United Kingdom",
origin="Mutation",
coat="Rex",
pattern="All",
),
Breed(
name="Donskoy, or Don Sphynx",
country="Russia",
origin="",
coat="Hairless",
pattern="",
),
Breed(
name="Dragon Li",
country="China",
origin="Natural",
coat="Short",
pattern="Striped tabby",
),
Breed(
name="Dwarf cat, or Dwelf",
country="",
origin="Crossbreed",
coat="",
pattern="Hairless",
),
Breed(
name="Egyptian Mau",
country="Egypt",
origin="Natural",
coat="Short",
pattern="Spotted",
),
Breed(
name="European Shorthair",
country="Finland and Sweden",
origin="Natural",
coat="Short",
pattern="",
),
Breed(
name="Exotic Shorthair",
country="United States",
origin="Crossbreed",
coat="Short",
pattern="All",
),
Breed(
name="Foldex[4]",
country="Canada",
origin="Crossbreed",
coat="Short",
pattern="All",
),
Breed(
name="German Rex",
country="East Germany",
origin="Mutation",
coat="Rex",
pattern="",
),
Breed(
name="Havana Brown",
country="United Kingdom",
origin="",
coat="Short",
pattern="Solid",
),
Breed(
name="Highlander",
country="United States",
origin="Crossbreed",
coat="Short/Long",
pattern="All",
),
Breed(
name="Himalayan, or Colorpoint Persian",
country="United States/United Kingdom",
origin="Crossbreed",
coat="Long",
pattern="Colorpoint",
),
Breed(
name="Japanese Bobtail",
country="Japan",
origin="Natural",
coat="Short/Long",
pattern="All but colorpoint and ticked",
),
Breed(
name="Javanese",
country="United States",
origin="Crossbreed",
coat="Long/Short",
pattern="Colorpoint",
),
Breed(
name="Karelian Bobtail",
country="Western Russia",
origin="Natural",
coat="",
pattern="",
),
Breed(
name="Khao Manee",
country="Thailand",
origin="Natural",
coat="Short",
pattern="Solid",
),
Breed(
name="Korat",
country="Thailand",
origin="Natural",
coat="Short",
pattern="Solid",
),
Breed(
name="Korean Bobtail",
country="Korea",
origin="Natural",
coat="Short/Long",
pattern="Colorprint",
),
Breed(
name="Korn Ja",
country="Thailand",
origin="Natural",
coat="Short/Hairless",
pattern="Solid",
),
Breed(
name="Kurilian Bobtail, or Kuril Islands Bobtail",
country="Eastern Russia,Japan",
origin="Natural",
coat="Short/Long",
pattern="",
),
Breed(
name="LaPerm",
country="United States",
origin="Mutation",
coat="Rex",
pattern="All",
),
Breed(
name="Lykoi",
country="United States",
origin="Natural/Mutation",
coat="Partly Hairless",
pattern="Ticked",
),
Breed(
name="Maine Coon",
country="United States",
origin="Natural",
coat="Long",
pattern="All but colorpoint and ticked",
),
Breed(
name="Manx",
country="United Kingdom",
origin="Mutation",
coat="Short/Long",
pattern="All but colorpoint",
),
Breed(
name="Mekong Bobtail",
country="Russia",
origin="Natural/Mutation",
coat="Short",
pattern="Colorpoint",
),
Breed(
name="Minskin",
country="United States",
origin="Crossbreed",
coat="Short/Hairless",
pattern="All",
),
Breed(
name="Munchkin",
country="United States",
origin="Mutation",
coat="",
pattern="",
),
Breed(
name="Nebelung",
country="United States",
origin="",
coat="Semi-long",
pattern="Solid",
),
Breed(
name="Napoleon",
country="",
origin="",
coat="Long/short",
pattern="Varied",
),
Breed(
name="Norwegian Forest cat",
country="Norway",
origin="Natural",
coat="Long",
pattern="All but colorpoint",
),
Breed(
name="Ocicat",
country="United States",
origin="Crossbreed",
coat="Short",
pattern="Spotted",
),
Breed(
name="Ojos Azules",
country="United States",
origin="",
coat="",
pattern="",
),
Breed(
name="Oregon Rex",
country="United States",
origin="Mutation",
coat="Rex",
pattern="",
),
Breed(
name="Oriental Bicolor",
country="",
origin="",
coat="",
pattern="Bicolor",
),
Breed(
name="Oriental Shorthair",
country="",
origin="",
coat="Short",
pattern="All but colorpoint",
),
Breed(
name="Oriental Longhair",
country="",
origin="",
coat="Semi-long",
pattern="",
),
Breed(
name="PerFoldæ(Experimental Breed - WCF),",
country="Europe",
origin="Crossbreed",
coat="Long",
pattern="All",
),
Breed(
name="Persian (Modern Persian Cat),",
country="Iran (Persia),",
origin="Crossbreed",
coat="Long",
pattern="All",
),
Breed(
name="Persian (Traditional Persian Cat),",
country="Greater Iran",
origin="Natural",
coat="Long",
pattern="All",
),
Breed(
name="Peterbald",
country="Russia",
origin="Crossbreed",
coat="Hairless",
pattern="All",
),
Breed(
name="Pixie-bob",
country="United States",
origin="Natural",
coat="Short",
pattern="Spotted",
),
Breed(
name="Raas",
country="Indonesia",
origin="Natural",
coat="Short",
pattern="",
),
Breed(
name="Ragamuffin",
country="United States",
origin="Crossbreed",
coat="Long",
pattern="All",
),
Breed(
name="Ragdoll",
country="United States",
origin="Crossbreed",
coat="Long",
pattern="Colorpoint/Mitted/Bicolor",
),
Breed(
name="Russian Blue",
country="Russia",
origin="Natural",
coat="Short",
pattern="Solid",
),
Breed(
name="Russian White, Black and Tabby",
country="Australia",
origin="Crossbreed",
coat="Short",
pattern="",
),
Breed(
name="Sam Sawet",
country="Thailand",
origin="Natural",
coat="Short",
pattern="Solid",
),
Breed(
name="Savannah",
country="United States",
origin="Hybrid",
coat="Short",
pattern="Spotted",
),
Breed(
name="Scottish Fold",
country="United Kingdom",
origin="Natural/Mutation",
coat="Short/Long",
pattern="All",
),
Breed(
name="Selkirk Rex",
country="United States",
origin="Mutation/Cross",
coat="Rex (Short/Long),",
pattern="All",
),
Breed(
name="Serengeti",
country="United States",
origin="Hybrid Crossbreed",
coat="Short",
pattern="Spotted",
),
Breed(
name="Serrade petit",
country="France",
origin="Natural",
coat="Short",
pattern="",
),
Breed(
name="Siamese",
country="Thailand",
origin="Natural",
coat="Short",
pattern="Colorpoint",
),
Breed(
name="Siberian",
country="Russia",
origin="Natural",
coat="Semi-long",
pattern="All",
),
Breed(
name="Singapura",
country="Singapore",
origin="Natural",
coat="Short",
pattern="Ticked",
),
Breed(
name="Snowshoe",
country="United States",
origin="Crossbreed",
coat="Short",
pattern="Colorpoint",
),
Breed(
name="Sokoke",
country="Kenya",
origin="Natural",
coat="Short",
pattern="Classic tabby with ticking",
),
Breed(
name="Somali",
country="Somalia",
origin="Mutation",
coat="Long",
pattern="Ticked",
),
Breed(
name="Sphynx",
country="Canada",
origin="Mutation",
coat="Hairless",
pattern="All",
),
Breed(
name="Suphalak",
country="Thailand",
origin="Natural",
coat="Short",
pattern="Solid",
),
Breed(
name="Thai",
country="Thailand",
origin="Natural",
coat="Short",
pattern="Colorpoint",
),
Breed(
name="Thai Lilac",
country="Thailand",
origin="Natural",
coat="Short",
pattern="Solid",
),
Breed(
name="Tonkinese",
country="Canada",
origin="Crossbreed",
coat="Short",
pattern="Colorpoint/Mink/Solid",
),
Breed(
name="Toyger",
country="United States",
origin="Crossbreed",
coat="Short",
pattern="Mackerel",
),
Breed(
name="Turkish Angora",
country="Turkey",
origin="Natural",
coat="Semi-long",
pattern="All but colorpoint",
),
Breed(
name="Ukrainian Levkoy",
country="Ukraine",
origin="",
coat="Hairless",
pattern="",
),
Breed(
name="York Chocolate",
country="United States",
origin="Natural",
coat="Long",
pattern="Solid",
),
]
def create_cat_breeds(apps, schema_editor):
CatBreed = apps.get_model("main", "CatBreed")
bulk = []
for cat_breed in cat_breeds:
bulk.append(
CatBreed(
name=cat_breed.name,
country=cat_breed.country,
origin=cat_breed.origin,
coat=cat_breed.coat,
pattern=cat_breed.pattern,
)
)
CatBreed.objects.bulk_create(bulk)
class Migration(migrations.Migration):
dependencies = [
("main", "0001_initial"),
]
operations = [
migrations.RunPython(create_cat_breeds),
]

View File

@ -1,333 +0,0 @@
# Generated by Django 5.0.4 on 2024-04-10 19:59
from django.db import migrations
post_offices = {
10000: 'Zagreb',
10010: 'Zagreb-Sloboština',
10020: 'Zagreb-Novi Zagreb',
10040: 'Zagreb-Dubrava',
10090: 'Zagreb-Susedgrad',
10104: 'Zagreb',
10105: 'Zagreb',
10108: 'Zagreb',
10109: 'Zagreb',
10110: 'Zagreb',
10135: 'Zagreb',
10172: 'Zagreb',
10250: 'Lučko',
10255: 'Gornji Stupnik',
10257: 'Brezovica',
10290: 'Zaprešić',
10291: 'Prigorje Brdovečko',
10292: 'Šenkovec',
10295: 'Kupljenovo',
10297: 'Jakovlje',
10298: 'Bistra',
10310: 'Ivanić Grad',
10315: 'Novoselec',
10340: 'Vrbovec',
10342: 'Dubrava',
10360: 'Sesvete',
10361: 'Sesvete Kraljevec',
10362: 'Kašina',
10370: 'Dugo Selo',
10380: 'Sveti Ivan Zelina',
10410: 'Velika Gorica',
10413: 'Kravarsko',
10414: 'Pokupsko',
10430: 'Samobor',
10431: 'Sveta Nedelja',
10435: 'Sveti Martin pod Okićem',
10437: 'Bestovje',
10450: 'Jastrebarsko',
10451: 'Pisarovina',
10454: 'Krašić',
20000: 'Dubrovnik',
20207: 'Mlini',
20210: 'Cavtat',
20215: 'Gruda',
20221: 'Koločep',
20222: 'Lopud',
20223: 'Šipanska Luka',
20225: 'Babino Polje',
20230: 'Ston',
20232: 'Slano',
20235: 'Zaton Veliki',
20236: 'Mokošica',
20240: 'Trpanj',
20244: 'Potomje',
20246: 'Janjina',
20250: 'Orebić',
20260: 'Korčula',
20270: 'Vela Luka',
20271: 'Blato',
20290: 'Lastovo',
20340: 'Ploče',
20350: 'Metković',
20355: 'Opuzen',
21000: 'Split',
21203: 'Donji Muć',
21204: 'Dugopolje',
21210: 'Solin',
21212: 'Kaštel Sućurac',
21214: 'Kaštel Kambelovac',
21217: 'Kaštel Štafilić',
21220: 'Trogir',
21222: 'Marina',
21225: 'Drvenik Veliki',
21230: 'Sinj',
21240: 'Trilj',
21232: 'Dicmo',
21233: 'Hrvace',
21236: 'Vrlika',
21238: 'Otok (Dalmacija)',
21250: 'Šestanovac',
21256: 'Cista Provo',
21260: 'Imotski',
21270: 'Zagvozd',
21276: 'Vrgorac',
21300: 'Makarska',
21310: 'Omiš',
21311: 'Stobreč',
21315: 'Dugi Rat',
21320: 'Baška Voda',
21327: 'Podgora',
21330: 'Gradac',
21400: 'Supetar',
21405: 'Milna',
21412: 'Pučišća',
21420: 'Bol',
21425: 'Selca',
21430: 'Grohote',
21450: 'Hvar',
21460: 'Stari Grad',
21465: 'Jelsa',
21469: 'Sućuraj',
21480: 'Vis',
21485: 'Komiža',
22000: 'Šibenik',
22202: 'Primošten',
22211: 'Vodice',
22213: 'Pirovac',
22222: 'Skradin',
22232: 'Zlarin',
22233: 'Prvić Luka',
22234: 'Prvić Šepurine',
22235: 'Kaprije',
22236: 'Žirje',
22240: 'Tisno',
22243: 'Murter',
22300: 'Knin',
22320: 'Drniš',
22323: 'Unešić',
23000: 'Zadar',
23205: 'Bibinje',
23206: 'Sukošan',
23210: 'Biograd na Moru',
23212: 'Tkon',
23222: 'Zemunik',
23223: 'Škabrnja',
23232: 'Nin',
23233: 'Privlaka',
23234: 'Vir',
23235: 'Vrsi',
23241: 'Poličnik',
23242: 'Posedarje',
23244: 'Starigrad Paklenica',
23248: 'Ražanac',
23250: 'Pag',
23271: 'Kukljica',
23273: 'Preko',
23281: 'Sali',
23283: 'Rava',
23284: 'Veli Iž',
23286: 'Božava',
23287: 'Veli Rat',
23291: 'Sestrunj',
23292: 'Molat',
23293: 'Ist',
23294: 'Premuda',
23295: 'Silba',
23296: 'Olib',
23312: 'Novigrad (Dalmacija)',
23420: 'Benkovac',
23422: 'Stankovci',
23440: 'Gračac',
23450: 'Obrovac',
31000: 'Osijek',
31200: 'Osijek',
31207: 'Tenja',
31226: 'Dalj',
31300: 'Beli Manastir',
31326: 'Darda',
31400: 'Đakovo',
31431: 'Čepin',
31500: 'Našice',
31540: 'Donji Miholjac',
31550: 'Valpovo',
31551: 'Belišće',
32000: 'Vukovar',
32100: 'Vinkovci',
32236: 'Ilok',
32242: 'Slakovci',
32249: 'Tovarnik',
32252: 'Otok',
32257: 'Drenovci',
32270: 'Županja',
32284: 'Stari Mikanovci',
33000: 'Virovitica',
33405: 'Pitomača',
33410: 'Suhopolje',
33515: 'Orahovica',
33520: 'Slatina',
34000: 'Požega',
34310: 'Pleternica',
34340: 'Kutjevo',
34550: 'Pakrac',
35000: 'Slavonski Brod',
35212: 'Garčin',
35214: 'Donji Andrijevci',
35220: 'Slavonski Šamac',
35222: 'Gundinci',
35250: 'Oriovac',
35252: 'Sibinj',
35400: 'Nova Gradiška',
35410: 'Nova Kapela',
35420: 'Staro Petrovo Selo',
35430: 'Okučani',
40000: 'Čakovec',
40313: 'Sveti Martin na Muri',
40315: 'Mursko Središče',
40320: 'Donji Kraljevec',
40323: 'Prelog',
42000: 'Varaždin',
42202: 'Trnovec Bartolovečki',
42204: 'Turčin',
42208: 'Cestica',
42220: 'Novi Marof',
42223: 'Varaždinske Toplice',
42230: 'Ludbreg',
42240: 'Ivanec',
42243: 'Maruševec',
42250: 'Lepoglava',
43000: 'Bjelovar',
43240: 'Čazma',
43270: 'Veliki Grđevac',
43280: 'Garešnica',
43290: 'Grubišno Polje',
43500: 'Daruvar',
44000: 'Sisak',
44010: 'Sisak-Caprag',
44210: 'Sunja',
44250: 'Petrinja',
44317: 'Popovača',
44320: 'Kutina',
44330: 'Novska',
44400: 'Glina',
44410: 'Vrginmost',
44430: 'Hrvatska Kostajnica',
44440: 'Dvor',
47000: 'Karlovac',
47220: 'Vojnić',
47240: 'Slunj',
47250: 'Duga Resa',
47280: 'Ozalj',
47300: 'Ogulin',
48000: 'Koprivnica',
48214: 'Sveti Ivan Žabno',
48260: 'Križevci',
48316: 'Đelekovec',
48350: 'Đurđevac',
49000: 'Krapina',
49210: 'Zabok',
49216: 'Desinić',
49217: 'Krapinske Toplice',
49218: 'Pregrada',
49221: 'Bedekovčina',
49223: 'Sveti Križ Začretje',
49225: 'Đurmanec',
49231: 'Hum na Sutli',
49240: 'Donja Stubica',
49243: 'Oroslavje',
49246: 'Marija Bistrica',
49250: 'Zlatar',
49252: 'Mihovljan',
49282: 'Konjščina',
49284: 'Budinščina',
49290: 'Klanjec',
51000: 'Rijeka',
51211: 'Matulji',
51215: 'Kastav',
51216: 'Viškovo',
51217: 'Klana',
51218: 'Dražice',
51224: 'Krasica',
51226: 'Hreljin',
51250: 'Novi Vinodolski',
51260: 'Crikvenica',
51262: 'Kraljevica',
51280: 'Rab',
51300: 'Delnice',
51306: 'Čabar',
51326: 'Vrbovsko',
51410: 'Opatija',
51415: 'Lovran',
51417: 'Mošćenička Draga',
51500: 'Krk',
51511: 'Malinska',
51523: 'Baška',
51550: 'Mali Lošinj',
51552: 'Ilovik',
51556: 'Martinšćica',
51557: 'Cres',
51561: 'Susak',
51562: 'Unije',
52000: 'Pazin',
52100: 'Pula (Pola)',
52207: 'Barban',
52210: 'Rovinj (Rovigno)',
52220: 'Labin',
52333: 'Podpićan',
52341: 'Žminj',
52420: 'Buzet',
52424: 'Motovun (Montona)',
52440: 'Poreč (Parenzo)',
52460: 'Buje (Buie)',
52466: 'Novigrad-Cittanova',
52470: 'Umag (Umago)',
53000: 'Gospić',
53202: 'Perušić',
53220: 'Otočac',
53230: 'Korenica',
53234: 'Udbina',
53250: 'Donji Lapac',
53260: 'Brinje',
53270: 'Senj',
53288: 'Karlobag',
53291: 'Novalja',
}
def create_post_offices(apps, schema_editor):
PostOffice = apps.get_model("main", "PostOffice")
bulk = []
for key, name in post_offices.items():
bulk.append(PostOffice(
zip=key,
name=name,
))
PostOffice.objects.bulk_create(bulk)
class Migration(migrations.Migration):
dependencies = [
("main", "0002_auto_20240410_1942"),
]
operations = [
migrations.RunPython(create_post_offices),
]

View File

@ -0,0 +1,60 @@
from django.db import migrations, models
def create_persons_data(apps, schema_editor):
Person = apps.get_model("main", "Person")
bulk = [
Person(
name="Pero",
address="Perina ulica 15",
city="Zagreb",
),
Person(
name="Mirko",
address="Mirkova ulica 17",
city="Zagreb",
),
Person(
name="Šime",
address="Šimina ulica 19",
city="Split",
),
Person(
name="Furio",
address="Furiozna ulica 21",
city="Pula",
),
]
Person.objects.bulk_create(bulk)
class Migration(migrations.Migration):
dependencies = [
("main", "0002_example_data"),
]
operations = [
migrations.CreateModel(
name="Person",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=100)),
("address", models.CharField(max_length=100)),
("city", models.CharField(max_length=100)),
],
options={
"db_table": "persons",
},
),
migrations.RunPython(create_persons_data),
]

View File

@ -0,0 +1,46 @@
# Generated by Django 5.0.4 on 2024-05-16 05:33
import django.core.validators
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("main", "0003_person"),
]
operations = [
migrations.AlterField(
model_name="person",
name="address",
field=models.CharField(
max_length=100,
validators=[
django.core.validators.MinLengthValidator(2),
django.core.validators.MaxLengthValidator(100),
],
),
),
migrations.AlterField(
model_name="person",
name="city",
field=models.CharField(
max_length=100,
validators=[
django.core.validators.MinLengthValidator(2),
django.core.validators.MaxLengthValidator(100),
],
),
),
migrations.AlterField(
model_name="person",
name="name",
field=models.CharField(
max_length=100,
validators=[
django.core.validators.MinLengthValidator(2),
django.core.validators.MaxLengthValidator(100),
],
),
),
]

View File

@ -1,11 +0,0 @@
# Generated by Django 5.0.4 on 2024-04-11 06:05
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("main", "0003_auto_20240410_1959"),
]
operations = []

View File

@ -1,3 +0,0 @@
from django.db import models
# Create your models here.

View File

@ -1,3 +1,2 @@
from .area import Area
from .county import County
from .post_office import PostOffice
from .cat_breed import CatBreed
from .person import Person

View File

@ -1,11 +0,0 @@
from django.db import models
class Area(models.Model):
name = models.CharField(max_length=100)
post_office = models.ForeignKey("PostOffice", on_delete=models.CASCADE)
county = models.ForeignKey("County", on_delete=models.CASCADE)
class Meta:
db_table = "areas"
ordering = ["name"]

View File

@ -0,0 +1,12 @@
from django.db import models
class CatBreed(models.Model):
name = models.CharField(max_length=100)
country = models.CharField(max_length=100)
origin = models.CharField(max_length=100)
coat = models.CharField(max_length=100)
pattern = models.CharField(max_length=100)
class Meta:
db_table = "cat_breeds"

View File

@ -1,9 +0,0 @@
from django.db import models
class County(models.Model):
name = models.CharField(max_length=100)
class Meta:
db_table = "counties"
ordering = ["name"]

View File

@ -0,0 +1,26 @@
from django.core.validators import MaxLengthValidator, MinLengthValidator
from django.db import models
class Person(models.Model):
name = models.CharField(
max_length=100,
blank=False,
null=False,
validators=[MinLengthValidator(2), MaxLengthValidator(100)],
)
address = models.CharField(
max_length=100,
blank=False,
null=False,
validators=[MinLengthValidator(2), MaxLengthValidator(100)],
)
city = models.CharField(
max_length=100,
blank=False,
null=False,
validators=[MinLengthValidator(2), MaxLengthValidator(100)],
)
class Meta:
db_table = "persons"

View File

@ -1,10 +0,0 @@
from django.db import models
class PostOffice(models.Model):
zip = models.PositiveIntegerField()
name = models.CharField(max_length=100)
class Meta:
db_table = "post_offices"
ordering = ["zip"]

View File

@ -6,6 +6,7 @@
content="width=100%, user-scalable=yes, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.min.js" integrity="sha384-BBtl+eGJRgqQAUMxJ7pMwbEyER4l1g+O15P+16Ep7Q9Q+zqX6gSbd85u4mG4QzX+" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
<script src="https://unpkg.com/htmx.org@1.9.11" integrity="sha384-0gxUXCCR8yv9FM2b+U3FDbsKthCI66oH5IA9fHppQq9DDMHuMauqq1ZHBpJxQ0J0" crossorigin="anonymous"></script>
<title>{{ title or "Django-html demo" }}</title>
</head>

View File

@ -0,0 +1,78 @@
{% macro inline_table_row(person) %}
<tr hx-target="this" hx-swap="outerHTML">
<td>{{ person.name }}</td>
<td>{{ person.address }}</td>
<td>{{ person.city }}</td>
<td>
<button
class="btn btn-outline-primary"
hx-get="{{ url("table-inline-edit-row", pk=person.pk) }}"
>
<i class="bi bi-pencil-square"></i>
</button>
</td>
</tr>
{% endmacro %}
{% macro inline_table_row_edit(person, cities, errors={}) %}
{% macro render_input(field_name, value) %}
{% set has_error = field_name in errors %}
<input
class="form-control {% if has_error %}is-invalid{% endif %}"
name="{{ field_name }}"
value="{{ value }}"
{% if has_error %}title="{{ errors[field_name] }}"{% endif %}
>
{% endmacro %}
{% macro render_select(field_name, value, options) %}
{% set has_error = field_name in errors %}
<select
class="form-select {% if has_error %}is-invalid{% endif %}"
name="{{ field_name }}"
{% if has_error %}title="{{ errors[field_name] }}"{% endif %}
>
{% for option in options %}
{% set selected = value == option %}
<option value="{{ option }}" {% if selected %}selected{% endif %}>
{{ option }}
</option>
{% endfor %}
</select>
{% endmacro %}
<tr
id="person-row-{{ person.pk }}"
hx-target="this"
hx-swap="outerHTML"
>
<td>
{{ render_input(field_name="name", value=person.name) }}
</td>
<td>
{{ render_input(field_name="address", value=person.address) }}
</td>
<td>
{# {{ render_input(field_name="city", value=person.city) }}#}
{{ render_select(field_name="city", value=person.city, options=cities) }}
</td>
<td>
<button
class="btn btn-outline-success"
hx-post="{{ url("table-inline-edit-row", pk=person.pk) }}"
hx-include="#person-row-{{ person.pk }} input, #person-row-{{ person.pk }} select"
>
<i class="bi bi-check-circle-fill"></i>
</button>
<button
class="btn btn-outline-danger"
hx-get="{{ url("table-inline-edit-row", pk=person.pk) }}"
hx-vals='{"action": "cancel"}'
>
<i class="bi bi-x-circle-fill"></i>
</button>
</td>
</tr>
{% endmacro %}

View File

@ -1,22 +1,14 @@
{% macro no_js_alert() %}
<div class="alert alert-success d-flex align-items-center mb-5" role="alert">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="text-success me-3" viewBox="0 0 16 16">
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zm-3.97-3.03a.75.75 0 0 0-1.08.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-.01-1.05z"/>
</svg>
<div>
No JavaScript is used creating this page.
</div>
<i class="bi bi-check-circle-fill me-3"></i>
No JavaScript is used creating this page.
</div>
{% endmacro %}
{% macro js_alert(content) %}
<div class="alert alert-warning d-flex align-items-center mb-5" role="alert">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="text-warning me-3" viewBox="0 0 16 16">
<path d="M8.982 1.566a1.13 1.13 0 0 0-1.96 0L.165 13.233c-.457.778.091 1.767.98 1.767h13.713c.889 0 1.438-.99.98-1.767L8.982 1.566zM8 5c.535 0 .954.462.9.995l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 5.995A.905.905 0 0 1 8 5zm.002 6a1 1 0 1 1 0 2 1 1 0 0 1 0-2z"/>
</svg>
<div>
{{ content }}
</div>
<i class="bi bi-exclamation-triangle-fill me-3"></i>
{{ content }}
</div>
{% endmacro %}

View File

@ -1,7 +1,54 @@
{% extends "main/base/layout.html" %}
{% from "main/components/js_alert.html" import js_alert_work_in_progress %}
{% from "main/components/js_alert.html" import no_js_alert %}
{% block content %}
{{ js_alert_work_in_progress() }}
{{ no_js_alert() }}
<div class="card mb-2">
<div class="card-body">
<form
class="row g-3 align-items-center"
>
<div class="col-auto">
<label class="form-label mb-0">Breed:</label>
</div>
<div class="col-auto">
<input
type="text"
name="breed"
class="form-control"
hx-get="{{ url("filter-list-filter") }}"
hx-target="#cat-breeds-table"
hx-trigger="keyup"
hx-include="select[name='country']"
/>
</div>
<div class="col-auto">
<label class="form-label mb-0">Country:</label>
</div>
<div class="col-auto">
<select
name="country"
class="form-select"
hx-get="{{ url("filter-list-filter") }}"
hx-target="#cat-breeds-table"
hx-trigger="change"
hx-include="input[name='breed']"
>
<option value="">
- All -
</option>
{% for country in countries %}
<option value="{{ country }}">
{{ country }}
</option>
{% endfor %}
</select>
</div>
</form>
</div>
</div>
{% include "main/filter_list_content.html" %}
{% endblock %}

View File

@ -0,0 +1,22 @@
<table class="table" id="cat-breeds-table">
<thead>
<tr>
<th>Breed</th>
<th>Country</th>
<th>Origin</th>
<th>Coat</th>
<th>Pattern</th>
</tr>
</thead>
<tbody>
{% for breed in cat_breeds %}
<tr>
<td>{{ breed.name }}</td>
<td>{{ breed.country }}</td>
<td>{{ breed.origin }}</td>
<td>{{ breed.coat }}</td>
<td>{{ breed.pattern }}</td>
</tr>
{% endfor %}
</tbody>
</table>

View File

@ -1,7 +1,24 @@
{% extends "main/base/layout.html" %}
{% from "main/components/js_alert.html" import js_alert_work_in_progress %}
{% from "main/components/js_alert.html" import no_js_alert %}
{% from "main/components/inline_table_row.html" import inline_table_row %}
{% block content %}
{{ js_alert_work_in_progress() }}
{{ no_js_alert() }}
<table class="table align-middle">
<thead>
<tr>
<th style="width: 25%">Name</th>
<th>Address</th>
<th style="width: 25%">City</th>
<th style="width: 15%">&nbsp;</th>
</tr>
</thead>
<tbody>
{% for person in persons %}
{{ inline_table_row(person) }}
{% endfor %}
</tbody>
</table>
{% endblock %}

View File

@ -0,0 +1,7 @@
{% from "main/components/inline_table_row.html" import inline_table_row, inline_table_row_edit %}
{% if is_editing %}
{{ inline_table_row_edit(person, cities=cities, errors=errors) }}
{% else %}
{{ inline_table_row(person) }}
{% endif %}

View File

@ -4,8 +4,8 @@ from .complex_form.views import (
RouteModuleHandleView,
WarehouseManagementHandleView,
)
from .filter_list import FilterListView
from .filter_list import FilterListFilterView, FilterListView
from .form_validation import FormValidationView
from .home import HomeView
from .swap import SwapView
from .table_inline_edit import TableInlineEditView
from .table_inline_edit import TableInlineEditView, TableInlineEditRowView

View File

@ -1,7 +1,67 @@
from typing import Any, Optional, Iterator
from django.db.models import Count, Q
from project.main.models import CatBreed
from project.main.views.demo_view_base import DemoViewBase
def get_countries() -> Iterator[str]:
ann = (
CatBreed.objects.values("country")
.annotate(Count("country"))
.order_by("country")
)
for a in ann:
yield a["country"]
def filter_cat_breeds(
breed_filter: Optional[str] = None, country_filter: Optional[str] = None
) -> Iterator[CatBreed]:
q = Q()
if breed_filter:
q &= Q(name__icontains=breed_filter)
if country_filter:
q &= Q(country=country_filter)
for c in CatBreed.objects.filter(q).order_by("name"):
yield c
class FilterListView(DemoViewBase):
template_name = "main/filter_list.html"
active_section = "filter-list"
title = "Filter List"
def get_context_data(self, **kwargs) -> dict[str, Any]:
context_data = super().get_context_data(**kwargs)
context_data.update(
{
"cat_breeds": filter_cat_breeds(),
"countries": get_countries(),
}
)
return context_data
class FilterListFilterView(DemoViewBase):
template_name = "main/filter_list_content.html"
def get_context_data(self, **kwargs) -> dict[str, Any]:
context_data = super().get_context_data(**kwargs)
cat_breeds = filter_cat_breeds(
breed_filter=self.request.GET.get("breed"),
country_filter=self.request.GET.get("country"),
)
context_data.update(
{
"cat_breeds": cat_breeds,
"countries": get_countries(),
}
)
return context_data

View File

@ -1,7 +1,88 @@
from typing import Any, Optional
from django.core.exceptions import ValidationError
from django.core.handlers.wsgi import WSGIRequest
from django.http import Http404, HttpResponse
from django.shortcuts import render
from project.main.models import Person
from project.main.views.demo_view_base import DemoViewBase
CITIES: list[str] = [
"",
"Zagreb",
"Split",
"Pula",
"Rijeka",
"Kozari bok",
]
def get_person(pk: int) -> Person:
try:
return Person.objects.get(pk=pk)
except Person.DoesNotExist:
raise Http404("Person not found")
class TableInlineEditView(DemoViewBase):
template_name = "main/table_inline_edit.html"
active_section = "table-inline-edit"
title = "Table Inline Edit"
def get_context_data(self, **kwargs) -> dict[str, Any]:
context_data = super().get_context_data(**kwargs)
persons = Person.objects.all()
context_data.update(
{
"persons": persons,
}
)
return context_data
class TableInlineEditRowView(DemoViewBase):
template_name = "main/table_inline_table_row.html"
def get_context_data(self, **kwargs) -> dict[str, Any]:
context_data = super().get_context_data(**kwargs)
person = get_person(pk=kwargs.get("pk"))
action = self.request.GET.get("action", "edit")
context_data.update(
{
"person": person,
"cities": CITIES,
"is_editing": action == "edit",
}
)
return context_data
def post(self, request: WSGIRequest, *args, **kwargs) -> HttpResponse:
errors: Optional[dict[str, str]] = None
person = get_person(pk=kwargs.get("pk"))
person.name = request.POST.get("name")
person.address = request.POST.get("address")
person.city = request.POST.get("city")
try:
person.clean_fields()
except ValidationError as ex:
errors = {key: value[0].message for key, value in ex.error_dict.items()}
else:
person.save()
return render(
context={
"person": person,
"errors": errors,
"cities": CITIES,
"is_editing": errors is not None,
},
template_name=self.template_name,
request=request,
)

View File

@ -6,10 +6,12 @@ urlpatterns = [
path("", views.HomeView.as_view(), name="home"),
path("swap", views.SwapView.as_view(), name="swap"),
path("filter-list", views.FilterListView.as_view(), name="filter-list"),
path("filter-list-filter", views.FilterListFilterView.as_view(), name="filter-list-filter"),
path("form-validation", views.FormValidationView.as_view(), name="form-validation"),
path("complex-form", views.ComplexFormView.as_view(), name="complex-form"),
path("complex-form/handle/route-module", views.RouteModuleHandleView.as_view(), name="complex-form-handle-route-module"),
path("complex-form/handle/reports", views.ReportsHandleView.as_view(), name="complex-form-handle-reports"),
path("complex-form/handle/warehouse-management", views.WarehouseManagementHandleView.as_view(), name="complex-form-handle-warehouse-management"),
path("table-inline-edit", views.TableInlineEditView.as_view(), name="table-inline-edit"),
path("table-inline-edit/edit/<int:pk>", views.TableInlineEditRowView.as_view(), name="table-inline-edit-row"),
]

View File

@ -6,7 +6,7 @@ authors = ["Eden Kirin <eden@ekirin.com>"]
readme = "README.md"
[tool.poetry.dependencies]
python = "^3.10"
python = ">= 3.10, < 3.12"
django = "^5.0.4"
django-jinja = "^2.11.0"
gunicorn = "^21.2.0"