Frambozenapp is a Python web application that showcases the Bozen library.
Bozen is a library that makes web development with Flask and MongoDB faster. (I'm using it in my MeowCat blogging platform.)
Bozen is:
- a Form library: renders and handles HTML forms
- a MongoDB ORM (terchnically a MongoDB ODM, since MongoDB isn't a relational database)
- several utility functions for web development
The most important classes in Bozen are:
- FormDoc, which handles HTML forms
- MonDoc, a subclass of
FormDoc
which knows how to get data into and out of a MongoDB database - the FieldInfo classes. Every field has an instance of a subclass of FieldInfo describing what data type it is and how it behaves in a form.
Other Bozen features:
- For a MonDoc, automatically generated autopages can perform BREAD (Browse, Read, Edit, Add, Delete) functionality for it.
- The Paginator class enables a table to be paginated so that only a certain number of rows appear on each page.
Requirements: Python 3.6, MongoDB, Git (to clone repository).
To start, first clone the repository locally.
$ git clone git@github.com:cabalamat/frambozenapp.git
$ cd frambozenapp
Create a virtual environment called v3
:
$ python3 -m venv v3
Go into your virtual environment:
$ . v3/bin/activate
Install the requirements:
$ pip install -r requirements.txt
Finally, go into the app/
directory and run the program. The
--debug
flag denotes that you are running it in debugging mode.
$ cd app
$ python main.py --debug
Now you can point your web browser at http://127.0.0.1:9033 to view the site.
Documentation is available in the ./doc/
directory. It's in the
extended markdown format that
CatWiki uses
(and was created in CatWiki), so is best viewed with CatWiki.
Test Form shows some of the form controls:
The Foos page shows a list of Foos (Foo being a collection in the database). Note that the pagination is handled by Bozen.
The Foo page shows a single Foo, and allows you to edit its
fields. The form is automatically denerated from the database schema
(in foo.py
):
DRINK_CHOICES = [
('beer', "Beer"),
('beer-lager', "Lager"),
('beer-frambozen', "Frambozen"),
('wine', "Wine"),
('spirits-whisky', "Whisky"),
('spirits-gin', "Gin"),
]
FRUIT_CHOICES = [
('apple', "Apple"),
('banana', "Banana"),
('strawberry', "Strawberry"),
('raspberry', "Raspberry"),
]
class Foo(MonDoc):
name = StrField()
description = TextAreaField(monospaced=True)
aNumber = IntField(minValue=0, maxValue=100)
minSpeed = FloatField(title="Minimum Speed, mph", minValue=0.0)
maxSpeed = FloatField(title="Maximim Speed, mph", minValue=0.0)
favouriteDrink = ChoiceField(choices=DRINK_CHOICES,
showNull=True, allowNull=True)
fruitsLiked = MultiChoiceField(choices=FRUIT_CHOICES,
desc="tick all fruits this person likes")
tickyBox = BoolField()
aDate = DateField()
lastSaved = DateTimeField(desc="when this foo was last saved",
readOnly=True)
aDateTime = DateTimeField(title="A Date and Time")
anything = ObjectField(desc="can contain anything",
default=["any", "thing"])
favouriteBook = FK(models.Book, allowNull=True, showNull=True)
Given the database schema for Foo
above, the /foos
and /foo
pages could have been automatically generated by this one line:
Foo.autopages()
(This wasn't done in the Foo example, for didactic purposes).