Django中Model类的工作原理及models.Model写法疑问
Great question! Let’s dive into the core mechanisms that make Django’s ORM automatically translate your model attributes into database columns. Since you’ve already sorted out why we use models.Model instead of directly referencing the base class, we’ll focus squarely on the attribute-to-column mapping process:
1. Metadata Collection via Metaclasses
When you define a model class that inherits from models.Model, Django uses a metaclass called ModelBase (under the hood in models.base) to process your class during initialization. Here’s what happens:
- The metaclass scans all attributes of your model class.
- It identifies attributes that are instances of
django.db.models.Field(likeCharField,IntegerField, etc.)—these are marked as database-backed fields, while regular Python attributes (like methods or class variables) are ignored for database mapping. - All these field instances are collected and stored in the model’s
_metaattribute—a special object that holds all metadata about the model, including field lists, table names, constraints, and relationships.
For example, if you have:
from django.db import models class Book(models.Model): title = models.CharField(max_length=200) publication_year = models.IntegerField()
The ModelBase metaclass will detect title and publication_year as fields, add them to Book._meta.fields, and ignore any other non-field attributes.
2. Field-to-Database Type Mapping
Each Field subclass comes with built-in logic to map to a specific database column type. Here’s how it works:
- Every field class has a
db_type()method that returns the appropriate SQL data type string for the active database backend (e.g., MySQL, PostgreSQL, SQLite). - Django’s database backends override or adjust these types to ensure compatibility. For example:
CharField(max_length=200)becomesVARCHAR(200)in MySQL, orVARCHAR(200)in PostgreSQL.DateTimeFieldmaps toDATETIMEin MySQL, butTIMESTAMP WITH TIME ZONEin PostgreSQL if you useauto_now_add=True.
- You can also customize the column type explicitly using the
db_typeparameter on a field, or override thedb_type()method for a custom field.
3. Migration & SQL Generation
Once your model is defined, Django uses migrations to translate the model structure into database schema changes:
- Running
makemigrationscompares your current model state against existing migration files, generating new migration scripts that describe the required changes (e.g., creating a new table, adding a column). - When you run
migrate, Django executes these migrations by converting them into raw SQL statements. For ourBookmodel, this would generate aCREATE TABLEstatement like:CREATE TABLE myapp_book ( id INTEGER PRIMARY KEY AUTOINCREMENT, title VARCHAR(200) NOT NULL, publication_year INTEGER NOT NULL ); - By default, the column name matches the model attribute name, but you can override this with the
db_columnparameter on a field.
4. Runtime Data Conversion
The ORM also handles bidirectional conversion between Python objects and database values:
- When reading data from the database, fields use the
from_db_value()method to convert raw database values into Python objects (e.g., turning a SQLDATETIMEstring into a Pythondatetimeobject). - When saving a model instance, fields use
get_prep_value()to convert Python objects into a format the database can accept (e.g., turning a Pythondatetimeinto a string compatible with the database’s date type).
Bonus: Field Constraints & Options
Additional field parameters translate directly to database column constraints:
null=Trueadds aNULLconstraint to the column.unique=Trueadds aUNIQUEconstraint.default=valuesets a default value for the column in the database.
内容的提问来源于stack exchange,提问作者William Karlsson

