jinja2+fastapi server up to working index page template
parent
000e4dad77
commit
ab0fba6ece
4
mach.nix
4
mach.nix
|
@ -1,4 +1,3 @@
|
|||
# [[file:poka-ijo.org::*=requirements.txt= and mach-nix setup][=requirements.txt= and mach-nix setup:2]]
|
||||
{ ... }:
|
||||
let
|
||||
mach-nix = import (builtins.fetchGit {
|
||||
|
@ -10,6 +9,5 @@ let
|
|||
in
|
||||
mach-nix.mkPythonShell {
|
||||
requirements = builtins.readFile ./requirements.txt;
|
||||
_.websockets.patchPhase = ""; #
|
||||
_.websockets.patchPhase = ""; #
|
||||
}
|
||||
# =requirements.txt= and mach-nix setup:2 ends here
|
||||
|
|
111
poka-ijo.org
111
poka-ijo.org
|
@ -3,7 +3,8 @@
|
|||
:ROAM_ALIASES: "FastAPI Personal Inventory" "My Inventory Application"
|
||||
:END:
|
||||
#+TITLE: Poka Ijo
|
||||
#+filetags: :Project:Programming:
|
||||
#+filetags: :Project:Programming:PokaIjo:
|
||||
#+AUTO_TANGLE: t
|
||||
|
||||
Poka Ijo is a catalog of my nearby things. Poka Ijo is [[id:tokipona][Tokipona]] for "nearby things", and it's a simple FastAPI application designed to run on my laptop or server and be used on my phone to quickly capture things in to my inventory, and run queries to determine where things are, and to find things that I should replace, donate, or maintain.
|
||||
|
||||
|
@ -13,11 +14,15 @@ CLOCK: [2021-09-18 Sat 16:33]--[2021-09-18 Sat 16:56] => 0:23
|
|||
:END:
|
||||
|
||||
** =requirements.txt= and mach-nix setup
|
||||
:PROPERTIES:
|
||||
:ID: 20210918T172447.506306
|
||||
:END:
|
||||
|
||||
#+begin_src txt :tangle requirements.txt :comments none
|
||||
fastapi
|
||||
uvicorn[standard]
|
||||
sqlmodel
|
||||
jinja2
|
||||
#+end_src
|
||||
|
||||
#+begin_src nix -r :tangle mach.nix
|
||||
|
@ -51,28 +56,80 @@ in pkgs.mkShell {
|
|||
#+end_src
|
||||
|
||||
** FastAPI Server initialization
|
||||
:PROPERTIES:
|
||||
:ID: 20210918T172533.031317
|
||||
:END:
|
||||
|
||||
#+begin_src :tangle server.py
|
||||
- Set up FastAPI
|
||||
- [[id:20210918T172550.522530][Create the DB]] using metadata attached to the =SQLModel= class
|
||||
- Set up Jinja2: =templates= is a [[https://fastapi.tiangolo.com/advanced/templates/][FastAPI]] helper which can easily render things tangled in to [[file:./templates/][./templates]].
|
||||
|
||||
#+begin_src python :tangle server.py :noweb yes
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.templating import Jinja2Templates
|
||||
|
||||
import poka_ijo.models as models
|
||||
|
||||
|
||||
app = FastAPI()
|
||||
engine = models.create_db_and_tables()
|
||||
templates = Jinja2Templates(directory="templates")
|
||||
|
||||
<<index-endpoints>>
|
||||
#+end_src
|
||||
|
||||
Some really basic template:
|
||||
|
||||
#+begin_src jinja2 :tangle templates/base.html.j2
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<link rel="manifest" href="/appmanifest.json">
|
||||
<title>{% block title %}Poka Ijo: Nearby Things{% endblock %}</title>
|
||||
{% block head %}{% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
<main role="main">
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
{% block footer %}
|
||||
<hr/>
|
||||
<p class="text-center">
|
||||
All content © 02021 Ryan Rix <<a href="mailto:site@whatthfuck.computer">site@whatthefuck.computer</a>>
|
||||
</p>
|
||||
{% endblock %}
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
#+end_src
|
||||
|
||||
* Data Models
|
||||
:LOGBOOK:
|
||||
CLOCK: [2021-09-18 Sat 16:56]--[2021-09-18 Sat 16:58] => 0:02
|
||||
:END:
|
||||
|
||||
#+begin_src python :tangle poka_ijo/models.py :noweb yes
|
||||
from typing import Optional
|
||||
from sqlmodel import Field, List, Relationship, SQLModel
|
||||
from typing import Optional, List
|
||||
from sqlmodel import Field, Relationship, SQLModel, create_engine
|
||||
|
||||
<<ThingTagLink>>
|
||||
<<Thing>>
|
||||
<<Tag>>
|
||||
<<Attachment>>
|
||||
|
||||
<<create_db_and_tables>>
|
||||
#+end_src
|
||||
|
||||
** =Thing= is a discrete object or collection in my Inventory
|
||||
:PROPERTIES:
|
||||
:ID: 20210918T172538.083873
|
||||
:END:
|
||||
|
||||
#+NAME: thing-desc
|
||||
God the definition of what a "thing" is loose-goosey and probably just gets figured out ad-hoc.
|
||||
|
@ -100,15 +157,21 @@ class Thing(SQLModel, table=True):
|
|||
#+end_src
|
||||
|
||||
** =Tag= is a simple string which can be joined against for a Good Time
|
||||
:PROPERTIES:
|
||||
:ID: 20210918T172541.240125
|
||||
:END:
|
||||
|
||||
#+begin_src python :noweb-ref Tag
|
||||
class Tag(SQLModel, table=True):
|
||||
id: Optiona[int] = Field(default=None, primary_key=True)
|
||||
id: Optional[int] = Field(default=None, primary_key=True)
|
||||
tag: str
|
||||
things: List["Thing"] = Relationship(back_populates="thing", link_model=ThingTagLink)
|
||||
#+end_src
|
||||
|
||||
** =ThingTagLink= is a Many-to-Many link between Things and Tags
|
||||
:PROPERTIES:
|
||||
:ID: 20210918T172543.888246
|
||||
:END:
|
||||
|
||||
[[https://sqlmodel.tiangolo.com/tutorial/many-to-many/create-models-with-link/][SQLModel docs]] on many-to-many:
|
||||
|
||||
|
@ -123,6 +186,9 @@ class ThingTagLink(SQLModel, table=True):
|
|||
#+end_src
|
||||
|
||||
** =Attachment= is a file that is relevant to a Thing
|
||||
:PROPERTIES:
|
||||
:ID: 20210918T172547.083917
|
||||
:END:
|
||||
|
||||
They'll be pictures of the thing I am capturing in to the system, they'll be PDFs of documentation or scans of receipts and inserts.
|
||||
|
||||
|
@ -139,6 +205,9 @@ class Attachment(SQLModel, table=True):
|
|||
#+end_src
|
||||
|
||||
** Model table creation
|
||||
:PROPERTIES:
|
||||
:ID: 20210918T172550.522530
|
||||
:END:
|
||||
|
||||
SQLModel gives us this "for free". Eventually this will go in a configuration file.
|
||||
|
||||
|
@ -146,22 +215,46 @@ SQLModel gives us this "for free". Eventually this will go in a configuration fi
|
|||
sqlite_file_name = "poka-ijo.db"
|
||||
sqlite_url = f"sqlite:///{sqlite_file_name}"
|
||||
|
||||
engine = create_engine(sqlite_url, echo=True)
|
||||
_engine = create_engine(sqlite_url, echo=True)
|
||||
|
||||
def engine():
|
||||
return _engine
|
||||
|
||||
def create_db_and_tables():
|
||||
SQLModel.metadata.create_all(engine)
|
||||
SQLModel.metadata.create_all(engine())
|
||||
return engine()
|
||||
#+end_src
|
||||
|
||||
* NEXT mobile-friendly capture interface
|
||||
|
||||
- image upload
|
||||
- image upload, clean up with imagemagick or so
|
||||
- fast metadata creation
|
||||
- "insert into"
|
||||
- "move to"
|
||||
|
||||
* NEXT index view
|
||||
|
||||
#+begin_src python :noweb-ref index-endpoints
|
||||
from fastapi.responses import HTMLResponse
|
||||
from fastapi import Request
|
||||
|
||||
@app.get("/", response_class=HTMLResponse)
|
||||
async def read_root(request: Request):
|
||||
return templates.TemplateResponse("index.html.j2", {"request": request})
|
||||
#+end_src
|
||||
|
||||
#+begin_src jinja2 :tangle templates/index.html.j2
|
||||
{% extends "base.html.j2" %}
|
||||
{% block title %}Index of Inventory{% endblock %}
|
||||
{% block head %}{% endblock %}
|
||||
{% block content %}
|
||||
<h1>Index</h1>
|
||||
<p class="important">
|
||||
Welcome to my awesome homepage.
|
||||
</p>
|
||||
{% endblock %}
|
||||
#+end_src
|
||||
|
||||
* NEXT search field
|
||||
|
||||
just a quick name -> thing search, maybe description, too
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
# [[file:../poka-ijo.org::*Data Models][Data Models:1]]
|
||||
from typing import Optional
|
||||
from sqlmodel import Field, List, Relationship, SQLModel
|
||||
from typing import Optional, List
|
||||
from sqlmodel import Field, Relationship, SQLModel, create_engine
|
||||
|
||||
class ThingTagLink(SQLModel, table=True):
|
||||
thing_id: Optional[int] = Field(
|
||||
|
@ -19,7 +18,7 @@ class Thing(SQLModel, table=True):
|
|||
attachments: List["Attachment"] = Relationship(back_populates="thing")
|
||||
tags: List["Tag"] = Relationship(back_populates="thing", link_model=ThingTagLink)
|
||||
class Tag(SQLModel, table=True):
|
||||
id: Optiona[int] = Field(default=None, primary_key=True)
|
||||
id: Optional[int] = Field(default=None, primary_key=True)
|
||||
tag: str
|
||||
things: List["Thing"] = Relationship(back_populates="thing", link_model=ThingTagLink)
|
||||
class Attachment(SQLModel, table=True):
|
||||
|
@ -29,13 +28,14 @@ class Attachment(SQLModel, table=True):
|
|||
|
||||
thing_id: Optional[int] = Field(default=None, foreign_key="thing.id")
|
||||
thing: Optional[Thing] = Relationship(back_populates="attachments")
|
||||
|
||||
sqlite_file_name = "poka-ijo.db"
|
||||
sqlite_url = f"sqlite:///{sqlite_file_name}"
|
||||
|
||||
engine = create_engine(sqlite_url, echo=True)
|
||||
_engine = create_engine(sqlite_url, echo=True)
|
||||
|
||||
def engine():
|
||||
return _engine
|
||||
|
||||
def create_db_and_tables():
|
||||
SQLModel.metadata.create_all(engine)
|
||||
# Data Models:1 ends here
|
||||
SQLModel.metadata.create_all(engine())
|
||||
return engine()
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
fastapi
|
||||
uvicorn[standard]
|
||||
sqlmodel
|
||||
jinja2
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.templating import Jinja2Templates
|
||||
|
||||
import poka_ijo.models as models
|
||||
|
||||
|
||||
app = FastAPI()
|
||||
engine = models.create_db_and_tables()
|
||||
templates = Jinja2Templates(directory="templates")
|
||||
|
||||
from fastapi.responses import HTMLResponse
|
||||
from fastapi import Request
|
||||
|
||||
@app.get("/", response_class=HTMLResponse)
|
||||
async def read_root(request: Request):
|
||||
return templates.TemplateResponse("index.html.j2", {"request": request})
|
|
@ -1,4 +1,3 @@
|
|||
# [[file:poka-ijo.org::*=requirements.txt= and mach-nix setup][=requirements.txt= and mach-nix setup:3]]
|
||||
let
|
||||
pkgs = import <nixpkgs> {};
|
||||
in pkgs.mkShell {
|
||||
|
@ -6,4 +5,3 @@ in pkgs.mkShell {
|
|||
pkgs.python3
|
||||
];
|
||||
}
|
||||
# =requirements.txt= and mach-nix setup:3 ends here
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<link rel="manifest" href="/appmanifest.json">
|
||||
<title>{% block title %}Poka Ijo: Nearby Things{% endblock %}</title>
|
||||
{% block head %}{% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
<main role="main">
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
{% block footer %}
|
||||
<hr/>
|
||||
<p class="text-center">
|
||||
All content © 02021 Ryan Rix <<a href="mailto:site@whatthfuck.computer">site@whatthefuck.computer</a>>
|
||||
</p>
|
||||
{% endblock %}
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,9 @@
|
|||
{% extends "base.html.j2" %}
|
||||
{% block title %}Index of Inventory{% endblock %}
|
||||
{% block head %}{% endblock %}
|
||||
{% block content %}
|
||||
<h1>Index</h1>
|
||||
<p class="important">
|
||||
Welcome to my awesome homepage.
|
||||
</p>
|
||||
{% endblock %}
|
Loading…
Reference in New Issue