jinja2+fastapi server up to working index page template

main
Ryan Rix 2021-09-18 18:12:47 -07:00
parent 000e4dad77
commit ab0fba6ece
8 changed files with 164 additions and 22 deletions

View File

@ -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

View File

@ -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 &copy; 02021 Ryan Rix &lt;<a href="mailto:site@whatthfuck.computer">site@whatthefuck.computer</a>&gt;
</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

View File

@ -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()

View File

@ -1,3 +1,4 @@
fastapi
uvicorn[standard]
sqlmodel
jinja2

18
server.py Normal file
View File

@ -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})

View File

@ -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

25
templates/base.html.j2 Normal file
View File

@ -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 &copy; 02021 Ryan Rix &lt;<a href="mailto:site@whatthfuck.computer">site@whatthefuck.computer</a>&gt;
</p>
{% endblock %}
</footer>
</body>
</html>

9
templates/index.html.j2 Normal file
View File

@ -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 %}