Fields

The Field class is used to describe the mapping of Model attributes to database columns. Each field type has a corresponding SQL storage class (i.e. varchar, int), and conversion between python data types and underlying storage is handled transparently.

When creating a Model class, fields are defined as class-level attributes. This should look familiar to users of the django framework. Here’s an example:

from peewee import *

class User(Model):
    username = CharField()
    join_date = DateTimeField()
    about_me = TextField()

There is one special type of field, ForeignKeyField, which allows you to expose foreign-key relationships between models in an intuitive way:

class Message(Model):
    user = ForeignKeyField(User, related_name='messages')
    body = TextField()
    send_date = DateTimeField()

This allows you to write code like the following:

>>> print some_message.user.username
Some User

>>> for message in some_user.messages:
...     print message.body
some message
another message
yet another message

Field types table

Parameters accepted by all field types and their default values:

  • null = False – boolean indicating whether null values are allowed to be stored
  • index = False – boolean indicating whether to create an index on this column
  • unique = False – boolean indicating whether to create a unique index on this column
  • verbose_name = None – string representing the “user-friendly” name of this field
  • help_text = None – string representing any helpful text for this field
  • db_column = None – string representing the underlying column to use if different, useful for legacy databases
  • default = None – any value to use as a default for uninitialized models
  • choices = None – an optional iterable containing 2-tuples of value, display
  • primary_key = False – whether this field is the primary key for the table
  • sequence = None – sequence to populate field (if backend supports it)
Field Type Sqlite Postgresql MySQL
CharField varchar varchar varchar
TextField text text longtext
DateTimeField datetime timestamp datetime
IntegerField integer integer integer
BooleanField smallint boolean bool
FloatField real real real
DoubleField real double precision double precision
BigIntegerField integer bigint bigint
DecimalField decimal numeric numeric
PrimaryKeyField integer serial integer
ForeignKeyField integer integer integer
DateField date date date
TimeField time time time

Some fields take special parameters...

Field type Special Parameters
CharField max_length
DateTimeField formats
DateField formats
TimeField formats
DecimalField max_digits, decimal_places, auto_round, rounding
ForeignKeyField rel_model, related_name, cascade, extra

A note on validation

Both default and choices could be implemented at the database level as DEFAULT and CHECK CONSTRAINT respectively, but any application change would require a schema change. Because of this, default is implemented purely in python and choices are not validated but exist for metadata purposes only.

Self-referential Foreign Keys

Since the class is not available at the time the field is declared, when creating a self-referential foreign key pass in ‘self’ as the “to” relation:

class Category(Model):
    name = CharField()
    parent = ForeignKeyField('self', related_name='children', null=True)

Implementing Many to Many

Peewee does not provide a “field” for many to many relationships the way that django does – this is because the “field” really is hiding an intermediary table. To implement many-to-many with peewee, you will therefore create the intermediary table yourself and query through it:

class Student(Model):
    name = CharField()

class Course(Model):
    name = CharField()

class StudentCourse(Model):
    student = ForeignKeyField(Student)
    course = ForeignKeyField(Course)

To query, let’s say we want to find students who are enrolled in math class:

for student in Student.select().join(StudentCourse).join(Course).where(Course.name == 'math'):
    print student.name

To query what classes a given student is enrolled in:

for course in Course.select().join(StudentCourse).join(Student).where(Student.name == 'da vinci'):
    print course.name

To efficiently iterate over a many-to-many relation, i.e., list all students and their respective courses, we will query the “through” model StudentCourse and “precompute” the Student and Course:

query = StudentCourse.select(
    StudentCourse, Student, Course)
).join(Course).switch(StudentCourse).join(Student)

To print a list of students and their courses you might do the following:

last = None
for student_course in query:
    student = student_course.student
    if student != last:
        last = student
        print 'Student: %s' % student.name
    print '    - %s' % student_course.course.name

Since we selected all fields from Student and Course in the select clause of the query, these foreign key traversals are “free” and we’ve done the whole iteration with just 1 query.

Non-integer Primary Keys

First of all, let me say that I do not think using non-integer primary keys is a good idea. The cost in storage is higher, the index lookups will be slower, and foreign key joins will be more expensive. That being said, here is how you can use non-integer pks in peewee.

from peewee import Model, PrimaryKeyField, VarCharColumn

class UUIDModel(Model):
    # explicitly declare a primary key field, and specify the class to use
    id = CharField(primary_key=True)

Auto-increment IDs are, as their name says, automatically generated for you when you insert a new row into the database. The way peewee determines whether to do an INSERT versus an UPDATE comes down to checking whether the primary key value is None. If None, it will do an insert, otherwise it does an update on the existing value. Since, with our uuid example, the database driver won’t generate a new ID, we need to specify it manually. When we call save() for the first time, pass in force_insert = True:

inst = UUIDModel(id=str(uuid.uuid4()))
inst.save() # <-- WRONG!!  this will try to do an update

inst.save(force_insert=True) # <-- CORRECT

# to update the instance after it has been saved once
inst.save()

Note

Any foreign keys to a model with a non-integer primary key will have the ForeignKeyField use the same underlying storage type as the primary key they are related to.

Field class API

class Field

The base class from which all other field types extend.

db_field = '<some field type>'

Attribute used to map this field to a column type, e.g. “string” or “datetime”

template = '%(column_type)s'

A template for generating the SQL for this field

__init__(null=False, index=False, unique=False, verbose_name=None, help_text=None, db_column=None, default=None, choices=None, *args, **kwargs)
Parameters:
  • null – this column can accept None or NULL values
  • index – create an index for this column when creating the table
  • unique – create a unique index for this column when creating the table
  • verbose_name – specify a “verbose name” for this field, useful for metadata purposes
  • help_text – specify some instruction text for the usage/meaning of this field
  • db_column – column class to use for underlying storage
  • default – a value to use as an uninitialized default
  • choices – an iterable of 2-tuples mapping value to display
  • primary_key (boolean) – whether to use this as the primary key for the table
  • sequence – name of sequence (if backend supports it)
db_value(value)
Parameters:value – python data type to prep for storage in the database
Return type:converted python datatype
python_value(value)
Parameters:value – data coming from the backend storage
Return type:python data type
coerce(value)

This method is a shorthand that is used, by default, by both db_value and python_value. You can usually get away with just implementing this.

Parameters:value – arbitrary data from app or backend
Return type:python data type
field_attributes()

This method is responsible for return a dictionary containing the default field attributes for the column, e.g. {'max_length': 255}

Return type:a python dictionary
class_prepared()

Simple hook for Field classes to indicate when the Model class the field exists on has been created.

class CharField

Stores: small strings (0-255 bytes)

class TextField

Stores: arbitrarily large strings

class DateTimeField

Stores: python datetime.datetime instances

Accepts a special parameter formats, which contains a list of formats the datetime can be encoded with. The default behavior is:

'%Y-%m-%d %H:%M:%S.%f' # year-month-day hour-minute-second.microsecond
'%Y-%m-%d %H:%M:%S' # year-month-day hour-minute-second
'%Y-%m-%d' # year-month-day

Note

If the incoming value does not match a format, it will be returned as-is

class DateField

Stores: python datetime.date instances

Accepts a special parameter formats, which contains a list of formats the date can be encoded with. The default behavior is:

'%Y-%m-%d' # year-month-day
'%Y-%m-%d %H:%M:%S' # year-month-day hour-minute-second
'%Y-%m-%d %H:%M:%S.%f' # year-month-day hour-minute-second.microsecond

Note

If the incoming value does not match a format, it will be returned as-is

class TimeField

Stores: python datetime.time instances

Accepts a special parameter formats, which contains a list of formats the time can be encoded with. The default behavior is:

'%H:%M:%S.%f' # hour:minute:second.microsecond
'%H:%M:%S' # hour:minute:second
'%H:%M' # hour:minute
'%Y-%m-%d %H:%M:%S.%f' # year-month-day hour-minute-second.microsecond
'%Y-%m-%d %H:%M:%S' # year-month-day hour-minute-second

Note

If the incoming value does not match a format, it will be returned as-is

class IntegerField

Stores: integers

class BooleanField

Stores: True / False

class FloatField

Stores: floating-point numbers

class DecimalField

Stores: decimal numbers

class PrimaryKeyField

Stores: auto-incrementing integer fields suitable for use as primary key.

class ForeignKeyField

Stores: relationship to another model

__init__(to[, related_name=None[, ...]])
Parameters:
  • rel_model – related Model class or the string ‘self’ if declaring a self-referential foreign key
  • related_name – attribute to expose on related model
class User(Model):
    name = CharField()

class Tweet(Model):
    user = ForeignKeyField(User, related_name='tweets')
    content = TextField()

# "user" attribute
>>> some_tweet.user
<User: charlie>

# "tweets" related name attribute
>>> for tweet in charlie.tweets:
...     print tweet.content
Some tweet
Another tweet
Yet another tweet