Plain is headed towards 1.0! Subscribe for development updates →

plain.models

Model your data and store it in a database.

# app/users/models.py
from plain import models
from plain.passwords.models import PasswordField


class User(models.Model):
    email = models.EmailField(unique=True)
    password = PasswordField()
    is_staff = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.email

Create, update, and delete instances of your models:

from .models import User


# Create a new user
user = User.objects.create(
    email="[email protected]",
    password="password",
)

# Update a user
user.email = "[email protected]"
user.save()

# Delete a user
user.delete()

# Query for users
staff_users = User.objects.filter(is_staff=True)

Installation

# app/settings.py
INSTALLED_PACKAGES = [
    ...
    "plain.models",
]

To connect to a database, you can provide a DATABASE_URL environment variable.

DATABASE_URL=postgresql://user:password@localhost:5432/dbname

Or you can manually define the DATABASES setting.

# app/settings.py
DATABASES = {
    "default": {
        "ENGINE": "plain.models.backends.postgresql",
        "NAME": "dbname",
        "USER": "user",
        "PASSWORD": "password",
        "HOST": "localhost",
        "PORT": "5432",
    }
}

Multiple backends are supported, including Postgres, MySQL, and SQLite.

Querying

Migrations

Migration docs

Fields

Field docs

Validation

Indexes and constraints

Managers

Forms

  1from plain.exceptions import ObjectDoesNotExist
  2
  3from . import (
  4    preflight,  # noqa
  5)
  6from .aggregates import *  # NOQA
  7from .aggregates import __all__ as aggregates_all
  8from .constraints import *  # NOQA
  9from .constraints import __all__ as constraints_all
 10from .db import (
 11    DEFAULT_DB_ALIAS,
 12    PLAIN_VERSION_PICKLE_KEY,
 13    DatabaseError,
 14    DataError,
 15    Error,
 16    IntegrityError,
 17    InterfaceError,
 18    InternalError,
 19    NotSupportedError,
 20    OperationalError,
 21    ProgrammingError,
 22    close_old_connections,
 23    connection,
 24    connections,
 25    reset_queries,
 26    router,
 27)
 28from .deletion import (
 29    CASCADE,
 30    DO_NOTHING,
 31    PROTECT,
 32    RESTRICT,
 33    SET,
 34    SET_DEFAULT,
 35    SET_NULL,
 36    ProtectedError,
 37    RestrictedError,
 38)
 39from .enums import *  # NOQA
 40from .enums import __all__ as enums_all
 41from .expressions import (
 42    Case,
 43    Exists,
 44    Expression,
 45    ExpressionList,
 46    ExpressionWrapper,
 47    F,
 48    Func,
 49    OrderBy,
 50    OuterRef,
 51    RowRange,
 52    Subquery,
 53    Value,
 54    ValueRange,
 55    When,
 56    Window,
 57    WindowFrame,
 58)
 59from .fields import *  # NOQA
 60from .fields import __all__ as fields_all
 61from .fields.json import JSONField
 62from .fields.proxy import OrderWrt
 63from .indexes import *  # NOQA
 64from .indexes import __all__ as indexes_all
 65from .lookups import Lookup, Transform
 66from .manager import Manager
 67from .query import Prefetch, QuerySet, prefetch_related_objects
 68from .query_utils import FilteredRelation, Q
 69
 70# Imports that would create circular imports if sorted
 71from .base import DEFERRED, Model  # isort:skip
 72from .fields.related import (  # isort:skip
 73    ForeignKey,
 74    ForeignObject,
 75    OneToOneField,
 76    ManyToManyField,
 77    ForeignObjectRel,
 78    ManyToOneRel,
 79    ManyToManyRel,
 80    OneToOneRel,
 81)
 82
 83
 84__all__ = aggregates_all + constraints_all + enums_all + fields_all + indexes_all
 85__all__ += [
 86    "ObjectDoesNotExist",
 87    "CASCADE",
 88    "DO_NOTHING",
 89    "PROTECT",
 90    "RESTRICT",
 91    "SET",
 92    "SET_DEFAULT",
 93    "SET_NULL",
 94    "ProtectedError",
 95    "RestrictedError",
 96    "Case",
 97    "Exists",
 98    "Expression",
 99    "ExpressionList",
100    "ExpressionWrapper",
101    "F",
102    "Func",
103    "OrderBy",
104    "OuterRef",
105    "RowRange",
106    "Subquery",
107    "Value",
108    "ValueRange",
109    "When",
110    "Window",
111    "WindowFrame",
112    "JSONField",
113    "OrderWrt",
114    "Lookup",
115    "Transform",
116    "Manager",
117    "Prefetch",
118    "Q",
119    "QuerySet",
120    "prefetch_related_objects",
121    "DEFERRED",
122    "Model",
123    "FilteredRelation",
124    "ForeignKey",
125    "ForeignObject",
126    "OneToOneField",
127    "ManyToManyField",
128    "ForeignObjectRel",
129    "ManyToOneRel",
130    "ManyToManyRel",
131    "OneToOneRel",
132]
133
134# DB-related exports
135__all__ += [
136    "connection",
137    "connections",
138    "router",
139    "reset_queries",
140    "close_old_connections",
141    "DatabaseError",
142    "IntegrityError",
143    "InternalError",
144    "ProgrammingError",
145    "DataError",
146    "NotSupportedError",
147    "Error",
148    "InterfaceError",
149    "OperationalError",
150    "DEFAULT_DB_ALIAS",
151    "PLAIN_VERSION_PICKLE_KEY",
152]