Indexes and Constraints

Peewee can create indexes on single or multiple columns, optionally including aUNIQUE constraint. Peewee also supports user-defined constraints on bothmodels and fields.

Single-column indexes and constraints

Single column indexes are defined using field initialization parameters. Thefollowing example adds a unique index on the username field, and a normalindex on the email field:

  1. class User(Model):
  2. username = CharField(unique=True)
  3. email = CharField(index=True)

To add a user-defined constraint on a column, you can pass it in using theconstraints parameter. You may wish to specify a default value as part ofthe schema, or add a CHECK constraint, for example:

  1. class Product(Model):
  2. name = CharField(unique=True)
  3. price = DecimalField(constraints=[Check('price < 10000')])
  4. created = DateTimeField(
  5. constraints=[SQL("DEFAULT (datetime('now'))")])

Multi-column indexes

Multi-column indexes may be defined as Meta attributes using a nested tuple.Each database index is a 2-tuple, the first part of which is a tuple of thenames of the fields, the second part a boolean indicating whether the indexshould be unique.

  1. class Transaction(Model):
  2. from_acct = CharField()
  3. to_acct = CharField()
  4. amount = DecimalField()
  5. date = DateTimeField()
  6.  
  7. class Meta:
  8. indexes = (
  9. # create a unique on from/to/date
  10. (('from_acct', 'to_acct', 'date'), True),
  11.  
  12. # create a non-unique on from/to
  13. (('from_acct', 'to_acct'), False),
  14. )

Note

Remember to add a trailing comma if your tuple of indexes contains only one item:

  1. class Meta:
  2. indexes = (
  3. (('first_name', 'last_name'), True), # Note the trailing comma!
  4. )

Advanced Index Creation

Peewee supports a more structured API for declaring indexes on a model usingthe Model.add_index() method or by directly using theModelIndex helper class.

Examples:

  1. class Article(Model):
  2. name = TextField()
  3. timestamp = TimestampField()
  4. status = IntegerField()
  5. flags = IntegerField()
  6.  
  7. # Add an index on "name" and "timestamp" columns.
  8. Article.add_index(Article.name, Article.timestamp)
  9.  
  10. # Add a partial index on name and timestamp where status = 1.
  11. Article.add_index(Article.name, Article.timestamp,
  12. where=(Article.status == 1))
  13.  
  14. # Create a unique index on timestamp desc, status & 4.
  15. idx = Article.index(
  16. Article.timestamp.desc(),
  17. Article.flags.bin_and(4),
  18. unique=True)
  19. Article.add_index(idx)

Warning

SQLite does not support parameterized CREATE INDEX queries. This meansthat when using SQLite to create an index that involves an expression orscalar value, you will need to declare the index using the SQLhelper:

  1. # SQLite does not support parameterized CREATE INDEX queries, so
  2. # we declare it manually.
  3. Article.add_index(SQL('CREATE INDEX ...'))

See add_index() for details.

For more information, see:

Table constraints

Peewee allows you to add arbitrary constraints to your Model, thatwill be part of the table definition when the schema is created.

For instance, suppose you have a people table with a composite primary key oftwo columns, the person’s first and last name. You wish to have another tablerelate to the people table, and to do this, you will need to define a foreignkey constraint:

  1. class Person(Model):
  2. first = CharField()
  3. last = CharField()
  4.  
  5. class Meta:
  6. primary_key = CompositeKey('first', 'last')
  7.  
  8. class Pet(Model):
  9. owner_first = CharField()
  10. owner_last = CharField()
  11. pet_name = CharField()
  12.  
  13. class Meta:
  14. constraints = [SQL('FOREIGN KEY(owner_first, owner_last) '
  15. 'REFERENCES person(first, last)')]

You can also implement CHECK constraints at the table level:

  1. class Product(Model):
  2. name = CharField(unique=True)
  3. price = DecimalField()
  4.  
  5. class Meta:
  6. constraints = [Check('price < 10000')]