Database and ORM
pantra is not bound to any ORM or database engine and works without any database needed. However, specifically
to flexible web framework needs I was designed QuazyDB ORM.
This section contains step-to-step guide to install connection to Postgres with QuazyDB.
Installation
QuazyDB is not included in general package, but it could be installed as optional package:
$ pip install pantra[quazydb,psycopg]
Note
psycopg is also required to connect to Postgres database.
Optionally, prepare empty database on Postgres:
CREATE USER pantra WITH PASSWORD 'pantra';
CREATE DATABASE pantra WITH OWNER pantra;
Then create apps/system/data/databases.xml:
databases.xml
<databases>
<postgres name="db" schema="system" conninfo="postgresql://pantra:pantra@localhost/pantra"/>
</databases>
System schema
Put several meta tables to test:
Click here to expand/collapse code
apps/system/data/__init__.py
import uuid
import hashlib
from quazy import *
from pantra.ctx import *
_SCHEMA_ = "system"
class Document(DBTable):
_lookup_field_ = 'number'
_meta_ = True
id: int = DBField(pk=True, ux=UX(blank=True, hidden=True))
number: int = DBField(ux=UX(width=6, blank=True))
date: datetime = DBField(default=datetime.now)
def __str__(self):
return f'{_(type(self).__name__)} - {self.number} - {session.locale.datetime(self.date)}'
class Row(DBTable):
_meta_ = True
pos: int = DBField(ux=UX(width=5))
data: FieldBody
class Catalog(DBTable):
_lookup_field_ = 'name'
_meta_ = True
id: int = DBField(pk=True, ux=UX(blank=True, hidden=True))
number: int = DBField(ux=UX(width=6, blank=True))
name: str | None
def __str__(self):
return self.name
@classmethod
def _view_(cls, item: DBQueryField[typing.Self]):
return item.name
def check_number(self, db: DBFactory):
table_class = self.__class__
if not self.number:
q = db.query(table_class)
max = (q
.exclude(id=q.arg(self.id).coalesce(0))
.fetch_max('number'))
self.number = max and max + 1 or 1
else:
look_up = db.get(table_class, number=self.number)
if look_up != self:
raise ValueError(f'Catalog number <{self.number}> is not unique')
def _before_insert(self, db: DBFactory):
self.check_number(db)
def _before_update(self, db: DBFactory):
self.check_number(db)
from pantra.models import expose_database
db = expose_database('system')
db.bind_module()
It is also recommended to generate stub file: apps/system/data/__init__.pyi:
$ pantra database.stub system
Then activate migrations:
$ pantra database.migration.activate system
Application schema
Put several files to run simple database application.
apps/storage/data/database.xml
<databases xmlns="app.datebases">
<reuse name="db" app="system" schema="storage"/>
</databases>
Click here to expand/collapse code
apps/storage/data/__init__.py
from __future__ import annotations
from apps.system.data import Catalog, Document
_SCHEMA_ = "storage"
class Storage(Catalog):
pass
class Unit(Catalog):
pass
class Good(Catalog):
unit: Unit
weight: float
class Purchase(Document):
storage: Storage
class Row(Document.Row):
good: Good
unit: Unit
qty: float
from pantra.models import expose_database
db = expose_database('storage')
db._debug_mode = True
db.bind_module()
Click here to expand/collapse code
apps/storage/Main.html
<GridR fullscreen fixed_header>
<section name="header">
<SysTray caption="#Storage management"/>
<Taskbar cref:taskbar/>
</section>
<section name="leftcol">
<SideMenu>
<MenuGroup caption="#Catalogs">
{{#for cat in catalogs}}
<MenuItem code="{cat}" action="@open_catalog"/>
{{/for}}
</MenuGroup>
<MenuGroup caption="#Documents">
<MenuItem caption="#Rest entries"/>
<MenuItem caption="#Sales"/>
<MenuItem caption="#Incomes"/>
</MenuGroup>
</SideMenu>
</section>
<section name="main">
<MDI/>
</section>
</GridR>
<python>
from components.helpers.db_tables import *
from pantra.ctx import *
catalogs = ['Storage', 'Good', 'Unit']
def init():
session.set_title(_('Storage management'))
def open_catalog(node):
render_list(session, node['code'])
</python>
Then apply migrations and create tables:
$ pantra database.migration.apply storage
That’s it. Ready to run:
Open your browser and enter URL http://localhost:8005/storage