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()
    password = PasswordField()
    is_admin = 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
admin_users = User.objects.filter(is_admin=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 .indexes import *  # NOQA
 63from .indexes import __all__ as indexes_all
 64from .lookups import Lookup, Transform
 65from .manager import Manager
 66from .query import Prefetch, QuerySet, prefetch_related_objects
 67from .query_utils import FilteredRelation, Q
 68from .registry import models_registry, register_model
 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    ManyToManyField,
 76    ForeignObjectRel,
 77    ManyToOneRel,
 78    ManyToManyRel,
 79)
 80
 81
 82__all__ = aggregates_all + constraints_all + enums_all + fields_all + indexes_all
 83__all__ += [
 84    "ObjectDoesNotExist",
 85    "CASCADE",
 86    "DO_NOTHING",
 87    "PROTECT",
 88    "RESTRICT",
 89    "SET",
 90    "SET_DEFAULT",
 91    "SET_NULL",
 92    "ProtectedError",
 93    "RestrictedError",
 94    "Case",
 95    "Exists",
 96    "Expression",
 97    "ExpressionList",
 98    "ExpressionWrapper",
 99    "F",
100    "Func",
101    "OrderBy",
102    "OuterRef",
103    "RowRange",
104    "Subquery",
105    "Value",
106    "ValueRange",
107    "When",
108    "Window",
109    "WindowFrame",
110    "JSONField",
111    "Lookup",
112    "Transform",
113    "Manager",
114    "Prefetch",
115    "Q",
116    "QuerySet",
117    "prefetch_related_objects",
118    "DEFERRED",
119    "Model",
120    "FilteredRelation",
121    "ForeignKey",
122    "ForeignObject",
123    "ManyToManyField",
124    "ForeignObjectRel",
125    "ManyToOneRel",
126    "ManyToManyRel",
127]
128
129# DB-related exports
130__all__ += [
131    "connection",
132    "connections",
133    "router",
134    "reset_queries",
135    "close_old_connections",
136    "DatabaseError",
137    "IntegrityError",
138    "InternalError",
139    "ProgrammingError",
140    "DataError",
141    "NotSupportedError",
142    "Error",
143    "InterfaceError",
144    "OperationalError",
145    "DEFAULT_DB_ALIAS",
146    "PLAIN_VERSION_PICKLE_KEY",
147]
148
149# Registry exports
150__all__ += ["register_model", "models_registry"]