Model options and table metadata

In order not to pollute the model namespace, model-specific configuration is placed in a special class called Meta (a convention borrowed from the django framework):

  1. from peewee import *
  2. contacts_db = SqliteDatabase('contacts.db')
  3. class Person(Model):
  4. name = CharField()
  5. class Meta:
  6. database = contacts_db

This instructs peewee that whenever a query is executed on Person to use the contacts database.

Note

Take a look at the sample models - you will notice that we created a BaseModel that defined the database, and then extended. This is the preferred way to define a database and create models.

Once the class is defined, you should not access ModelClass.Meta, but instead use ModelClass._meta:

  1. >>> Person.Meta
  2. Traceback (most recent call last):
  3. File "<stdin>", line 1, in <module>
  4. AttributeError: type object 'Person' has no attribute 'Meta'
  5. >>> Person._meta
  6. <peewee.ModelOptions object at 0x7f51a2f03790>

The ModelOptions class implements several methods which may be of use for retrieving model metadata (such as lists of fields, foreign key relationships, and more).

  1. >>> Person._meta.fields
  2. {'id': <peewee.AutoField object at 0x7f51a2e92750>,
  3. 'name': <peewee.CharField object at 0x7f51a2f0a510>}
  4. >>> Person._meta.primary_key
  5. <peewee.AutoField object at 0x7f51a2e92750>
  6. >>> Person._meta.database
  7. <peewee.SqliteDatabase object at 0x7f519bff6dd0>

There are several options you can specify as Meta attributes. While most options are inheritable, some are table-specific and will not be inherited by subclasses.

OptionMeaningInheritable?
databasedatabase for modelyes
table_namename of the table to store datano
table_functionfunction to generate table name dynamicallyyes
indexesa list of fields to indexyes
primary_keya CompositeKey instanceyes
constraintsa list of table constraintsyes
schemathe database schema for the modelyes
only_save_dirtywhen calling model.save(), only save dirty fieldsyes
optionsdictionary of options for create table extensionsyes
table_settingslist of setting strings to go after close parenthesesyes
temporaryindicate temporary tableyes
legacy_table_namesuse legacy table name generation (enabled by default)yes
depends_onindicate this table depends on another for creationno
without_rowidindicate table should not have rowid (SQLite only)no

Here is an example showing inheritable versus non-inheritable attributes:

  1. >>> db = SqliteDatabase(':memory:')
  2. >>> class ModelOne(Model):
  3. ... class Meta:
  4. ... database = db
  5. ... table_name = 'model_one_tbl'
  6. ...
  7. >>> class ModelTwo(ModelOne):
  8. ... pass
  9. ...
  10. >>> ModelOne._meta.database is ModelTwo._meta.database
  11. True
  12. >>> ModelOne._meta.table_name == ModelTwo._meta.table_name
  13. False

Meta.primary_key

The Meta.primary_key attribute is used to specify either a CompositeKey or to indicate that the model has no primary key. Composite primary keys are discussed in more detail here: Composite primary keys.

To indicate that a model should not have a primary key, then set primary_key = False.

Examples:

  1. class BlogToTag(Model):
  2. """A simple "through" table for many-to-many relationship."""
  3. blog = ForeignKeyField(Blog)
  4. tag = ForeignKeyField(Tag)
  5. class Meta:
  6. primary_key = CompositeKey('blog', 'tag')
  7. class NoPrimaryKey(Model):
  8. data = IntegerField()
  9. class Meta:
  10. primary_key = False

Table Names

By default Peewee will automatically generate a table name based on the name of your model class. The way the table-name is generated depends on the value of Meta.legacy_table_names. By default, legacy_table_names=True so as to avoid breaking backwards-compatibility. However, if you wish to use the new and improved table-name generation, you can specify legacy_table_names=False.

This table shows the differences in how a model name is converted to a SQL table name, depending on the value of legacy_table_names:

Model namelegacy_table_names=Truelegacy_table_names=False (new)
Useruseruser
UserProfileuserprofileuser_profile
APIResponseapiresponseapi_response
WebHTTPRequestwebhttprequestweb_http_request
mixedCamelCasemixedcamelcasemixed_camel_case
Name2Numbers3XYZname2numbers3xyzname2_numbers3_xyz

Attention

To preserve backwards-compatibility, the current release (Peewee 3.x) specifies legacy_table_names=True by default.

In the next major release (Peewee 4.0), legacy_table_names will have a default value of False.

To explicitly specify the table name for a model class, use the table_name Meta option. This feature can be useful for dealing with pre-existing database schemas that may have used awkward naming conventions:

  1. class UserProfile(Model):
  2. class Meta:
  3. table_name = 'user_profile_tbl'

If you wish to implement your own naming convention, you can specify the table_function Meta option. This function will be called with your model class and should return the desired table name as a string. Suppose our company specifies that table names should be lower-cased and end with “_tbl”, we can implement this as a table function:

  1. def make_table_name(model_class):
  2. model_name = model_class.__name__
  3. return model_name.lower() + '_tbl'
  4. class BaseModel(Model):
  5. class Meta:
  6. table_function = make_table_name
  7. class User(BaseModel):
  8. # table_name will be "user_tbl".
  9. class UserProfile(BaseModel):
  10. # table_name will be "userprofile_tbl".