Skip to content
A small, schemaless Python ORM that is backed by SQLite.
Branch: master
Clone or download

Latest commit

Fetching latest commit…
Cannot retrieve the latest commit at this time.


Type Name Latest commit message Commit time
Failed to load latest commit information.
goatfish fix next() function for python2.5 compatibility Aug 21, 2013
.travis.yml Remove Python 2.5 support. Oct 4, 2013
COPYING Initial commit. Feb 15, 2012 Add Code Shelter badge Dec 14, 2018 Initial commit. Feb 15, 2012


Build Status Code Shelter

goatfish is a small, schemaless ORM that is backed by SQLite.

It's also this:

A goatfish

Its usage is very simple, just have your classes inherit from goatfish.Model and and specify a connection, and the goatfish methods are available to you. goatfish also supports querying for arbitrary properties in your models, as well as indexing on arbitrary properties. It does not enforce a schema of any kind.

It appears that this method is identical to what FriendFeed used to implement a schemaless layer over MySQL, which is pretty significant validation:


To use goatfish, all you need to do is create a class that inherits from goatfish.Model:

import goatfish
import sqlite3

class Test(goatfish.Model):
    class Meta:
        # This is so we know where to connect.
        connection = sqlite3.connect(":memory:")
        indexes = (
            ("foo", "bar"),

# Create the necessary tables. If they exist, do nothing.

foo = Test() = "hi" = "hello"

# Retrieve all elements.
>>> [ for test in Test.find()]

# Run a query with parameters (slow, loads every item from the DB to check it).
>>> [ for test in Test.find({"bar": "hello"})]

# This uses an index, so it's fast.
>>> [ for test in Test.find({"foo": "hi"})]

# Run a query with a parameter that doesn't exist in the dataset.
>>> [ for test in Test.find({"bar": "hello", "baz": "hi"})]

>>> Test.find_one({"bar": "hello"}).foo

>>> print(Test.find_one({"bar": "doesn't exist"}))

# Delete the element.
>>> foo.delete()

# Try to retrieve all elements again.
>>> [ for test in Test.find()]


What sets goatfish apart from other modules such as shelve, zodb, etc is its ability to query random attributes, and make those queries faster by using SQLite indexes.

The way this is achieved is by creating an intermediate table for each index we specify. The index tables consist of the uuid column, and one column for every field in the index. This way, we can store the value itself in these index tables and query them quickly, as the rows have SQLite indexes themselves.

The find() method uses these indexes automatically, if they exist, to avoid sequential scans. It will automatically use the largest index that contains the data we want to query on, so a query of {"foo": 3, "bar": 2} when only foo is indexed will use the index on foo to return the data, and do a sequential scan to match bar.

Right now, new indexes are only populated with data on save(), so you might miss rows when querying on indexes that are not ready yet. To populate indexes, go through the objects in your model and perform a save() in each of them. Convenience functions to populate single indexes will be provided shortly.


To install goatfish you need:

  • Python 2.5 or later in the 2.x line (3.x and earlier than 2.5 not tested).

You have multiple options of installation:


goatfish is distributed under the BSD license.

You can’t perform that action at this time.