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):
from peewee import *
contacts_db = SqliteDatabase('contacts.db')
class Person(Model):
name = CharField()
class Meta:
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
:
>>> Person.Meta
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'Person' has no attribute 'Meta'
>>> Person._meta
<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).
>>> Person._meta.fields
{'id': <peewee.PrimaryKeyField object at 0x7f51a2e92750>,
'name': <peewee.CharField object at 0x7f51a2f0a510>}
>>> Person._meta.primary_key
<peewee.PrimaryKeyField object at 0x7f51a2e92750>
>>> Person._meta.database
<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.
Here is an example showing inheritable versus non-inheritable attributes:
>>> db = SqliteDatabase(':memory:')
>>> class ModelOne(Model):
... class Meta:
... database = db
... table_name = 'model_one_tbl'
...
>>> class ModelTwo(ModelOne):
... pass
...
>>> ModelOne._meta.database is ModelTwo._meta.database
True
>>> ModelOne._meta.table_name == ModelTwo._meta.table_name
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:
class BlogToTag(Model):
"""A simple "through" table for many-to-many relationship."""
blog = ForeignKeyField(Blog)
tag = ForeignKeyField(Tag)
class Meta:
primary_key = CompositeKey('blog', 'tag')
class NoPrimaryKey(Model):
data = IntegerField()
class Meta:
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 name | legacy_table_names=True | legacy_table_names=False (new) |
---|---|---|
User | user | user |
UserProfile | userprofile | user_profile |
APIResponse | apiresponse | api_response |
WebHTTPRequest | webhttprequest | web_http_request |
mixedCamelCase | mixedcamelcase | mixed_camel_case |
Name2Numbers3XYZ | name2numbers3xyz | name2_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:
class UserProfile(Model):
class Meta:
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:
def make_table_name(model_class):
model_name = model_class.__name__
return model_name.lower() + '_tbl'
class BaseModel(Model):
class Meta:
table_function = make_table_name
class User(BaseModel):
# table_name will be "user_tbl".
class UserProfile(BaseModel):
# table_name will be "userprofile_tbl".