Skip to main content

A minimalistic ORM with basic features.

Project description

A minimalistic ORM with basic features.

Inspired by Django ORM.

What’s the point?

MinORM was designed as minimalistic ORM, to be as simple as possible. It’s not production-ready solution, rather a proof of concept. The goal is to demonstrate example of an ORM, more-less applicable for usage, that could be created with python in a couple of days.

Usage

DB Connection

Establish connection to database by calling .connect() method of connector object, with certain db handler.

Connecting to sqlite database:

from minorm.connectors import connector
from minorm.db_specs import SQLiteSpec

connector.connect(SQLiteSpec('example.db'))

Connecting to postgresql database (requires psycopg2 to be installed):

from minorm.connectors import connector
from minorm.db_specs import PostgreSQLSpec

connection_string = "host=localhost port=5432 dbname=mydb user=admin password=secret"
connector.connect(PostgreSQLSpec(connection_string))

Close connection by calling .disconnect() method:

connector.disconnect()

Models

Create a model class that represents a single table in a database:

from minorm.models import Model
from minorm.fields import CharField, IntegerField

class Person(Model):
    name = CharField(max_length=120)
    age = IntegerField()

It’s possible to create a new table in a database:

Person.create_table()

Or to use existing one, by set table name in model meta:

class Book(Model):
    title = CharField(max_length=90)

    class Meta:
        table_name = "some_table"

It’s possible to drop a table:

Person.drop_table()

Create a new instance or update existing one in db by calling save method:

person = Person()
person.name = "John" # set field values as attributes
person.age = 33
person.save()

book = Book(title="foobar")  # or pass it in init method
book.save()

Remove a row from db by calling delete method:

person.delete()

Create a model with foreign relation by using ForeignKey field:

class Book(Model):
    title = CharField(max_length=90)
    author = ForeignKey(Person)

Pass an instance of related model when saving a new one:

book = Book(title="foobar", author=person)
book.save()

Queryset methods

Use queryset, accessible by model’s qs property, to perform db operations on multiple rows:

all():

Get all rows as a list of namedtuple objects:

persons = Person.qs.all()  # list of namedtuples

it’s possible to limit number of selected rows by using slices:

persons = Person.qs[:3].all()  # list with only three items
values(*fields):

Prepare qs to get rows as dictionaries with fields, passed to the method:

values_qs = Book.qs.values('title', 'author__name')  # dicts with this two keys
books = values_qs.all()  # this method call will actually hit db, not previous
filter(**lookups):

Filter query, result will contain only items that matches all lookups:

# user type is "member" AND age > 18
filtered_qs = Person.qs.filter(user_type='member', age__gt=18)
result = filtered_qs.all()  # hits db, performs select query

List of supported lookup expressions:

  • lt, lte - less than (or equal)

  • gt, gte - greater than (or equal)

  • neq - not equal

  • in - checks if value is between given options

  • startswith, endswith, contains - check inclusion of a string

It’s also possible to filter by foreign relation fields:

qs = Book.qs.filter(author__name="Mark Twain", price__lt=42)
result = qs.all()  # will perform join of `author` table
aswell(**lookups):

Make query result to include items that also matches lookups listed in the method:

# age > 18 OR user is admin
filtered_qs = Person.qs.filter(age__gt=18).aswell(user_type="admin")
order_by(*fields):

Set ordering of queried rows. Use - prefix to reverse order:

Book.qs.order_by('created')  # for oldest to newest
Person.qs.order_by('-id')  # reverse ordering by id
exists():

Return boolean, that indicates presence of rows that match filters:

Person.qs.filter(name="mike").exists()  # True if there is such name, otherwise False
Book.qs.exists()  # check if there is at least one row in the table
get(**lookups):

Get single row as an instance of the model class:

person = Person.qs.get(id=7)  # model instance object
book = Book.qs.get(pk=7)  # you could use `pk` instead of pk field name

raises Model.DoesNotExists if corresponding row not found in db, and MultipleQueryResult if more than one row matches query filters.

create(**field_values):

Create a new instance in db:

person = Person.qs.create(name="John", age=33)

is a shortcut for two calls:

person = Person(name="John", age=33)
person.save()
update(**field_values):

Update field values of existing rows in db:

Book.qs.filter(price__lt=200).update(price=250)
delete():

Remove all rows of queryset from db:

Product.qs.filter(created__lt=date(2020, 11, 10)).delete()
bulk_create(instances):

Create multiple instances in one db query:

Book.qs.bulk_create([
    Book(title="foo", author=1),
    Book(title="bar", author=2),
    Book(title="baz", author=1),
])  # creates all these books in one query
select_related(*fk_fields):

Prepare queryset to perform select query with join of foreign relation:

for book in Book.qs.select_related('author').all():
    author = book.author  # without select_related call, each author will hit db
    print(book.title, author.name)

TODO

  • add more model fields

  • test Postgresql support

  • add basic aggregation functions (SUM, COUNT, etc)

  • add transaction support

Running tests

To run tests, create virtual environment and then run:

make test

License

The MIT License (MIT)

Contributed by Campos Ilya

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

minorm-0.4.1.tar.gz (14.5 kB view details)

Uploaded Source

Built Distribution

minorm-0.4.1-py3-none-any.whl (14.5 kB view details)

Uploaded Python 3

File details

Details for the file minorm-0.4.1.tar.gz.

File metadata

  • Download URL: minorm-0.4.1.tar.gz
  • Upload date:
  • Size: 14.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.3.0 pkginfo/1.6.1 requests/2.25.1 setuptools/40.8.0 requests-toolbelt/0.9.1 tqdm/4.56.0 CPython/3.7.3

File hashes

Hashes for minorm-0.4.1.tar.gz
Algorithm Hash digest
SHA256 f95b21257cfa5f9b31bf9f90e0b4f832793bc62cd8c5d69917b3be59b9f408d0
MD5 085f4ed835f4927043acab36ff8c5274
BLAKE2b-256 c40f91f90042895c7a9140b4dc08fce643d4320bf0ad7d0fb9852f4768039cba

See more details on using hashes here.

File details

Details for the file minorm-0.4.1-py3-none-any.whl.

File metadata

  • Download URL: minorm-0.4.1-py3-none-any.whl
  • Upload date:
  • Size: 14.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.3.0 pkginfo/1.6.1 requests/2.25.1 setuptools/40.8.0 requests-toolbelt/0.9.1 tqdm/4.56.0 CPython/3.7.3

File hashes

Hashes for minorm-0.4.1-py3-none-any.whl
Algorithm Hash digest
SHA256 3d421f27925c3a89ffcf5ffe5222bf82a23ea690f1d4bd074e9f56e0f06f8d11
MD5 2b5bdb2597c4882b3aadbf48ef7f90b3
BLAKE2b-256 dc7adfc5c7289bea1e2a16b804503dc5da8541ec007d15a5c2e2046e8975567c

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page