Django 1.8 official document translation: 2-1-1 model syntax

Time:2021-6-16

Model

Models are the only authoritative source of information for your data. It contains the necessary fields and behaviors for the data you store. Generally, each model corresponds to a unique table in the database.

Basics:

  • Every model isdjango.db.models.ModelA python subclass of.

  • Each attribute of the model represents a field in the database.

  • Django provides a set of automatically generated API for database access; See_ Execute query_

A short example

This example defines aPersonModel, it hasfirst_nameandlast_nameThere are two attributes

from django.db import models

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

first_nameandlast_nameIt’s two parts of the modelfield. Each field is designated as a class property, and each property is mapped to a database column.

abovePersonThe model creates such a table in the database:

CREATE TABLE myapp_person (
    "id" serial NOT NULL PRIMARY KEY,
    "first_name" varchar(30) NOT NULL,
    "last_name" varchar(30) NOT NULL
);

Some technical considerations:

  • The name of this tablemyapp_person, is automatically generated according to the metadata in the model, and can also be overridden as other names. See_Table names_

  • id  Fields are added automatically, but this behavior can be overridden. See_ Auto increment primary key field_

  • In this caseCREATE TABLESQL statements use PostgreSQL syntax format, it should be noted that Django will_ Setup file_To use the corresponding SQL statement.

Usage model

After defining the model, you need to tell Django_ Use_ These models. All you have to do is modify theINSTALLED_APPS  Settings, addingmodels.pyThe name of the app.

For example, if the model of your application is located inmyapp.modelsModule(manage.py startappA package structure created by a script for an application,INSTALLED_APPSPart of it looks like:

INSTALLED_APPS = (
    #...
    'myapp',
    #...
)

When you areINSTALLED_APPSWhen you add a new application name to, make sure you run the commandmanage.py migrate, which can be used firstmanage.py makemigrationsTo generate migration scripts for them.

field

The most important and indispensable part of the model is the field set, which is a list of database fields. Field is specified as a class property. Note that the selected field name should not be the same as the field name_ Model API_Conflicts, such ascleansaveperhapsdelete

For example:

from django.db import models

class Musician(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    instrument = models.CharField(max_length=100)

class Album(models.Model):
    artist = models.ForeignKey(Musician)
    name = models.CharField(max_length=100)
    release_date = models.DateField()
    num_stars = models.IntegerField()

Field type

Each field in the model isFieldAn instance of a subclass. Django determines the following information based on the type of field class:

  • Column types in the database (for example,  INTEGER, VARCHAR)。

  • The default HTML to use when rendering forms_ Components_(for example,<input type="text">, <select>)。

  • Minimal validation requirements, which are used in Django administration sites and automatically generated forms.

Django has dozens of built-in field types; A complete list of field types can be found in the_ Model field reference_Found in. If the built-in type still can’t meet your requirements, you can freely write the field type that meets your requirements; See_ Write custom model fields_

field option

Each field has some unique parameters, as shown in_ Model field reference_. For example,CharField(and its derived classes) requiresmax_lengthParameterVARCHARThe size of the database field.

There are also some common parameters for all fields.   These parameters are in the_ Reference_Here we will briefly introduce some of the most commonly used:

null

IfTrue, Django will useNULLTo store null values in the database. The default value isFalse.

blank

IfTrue, this field is not allowed to be filled in. Default toFalse

Note that this is related tonull  Different.nullIt’s purely database, not databaseblankIt’s in the field of data validation. If theblank=TrueThe validation of the form will allow the field to be null. If theblank=False, which is required.

choices

An iteratable object (for example, a list or a tuple) consisting of two tuples used to provide options for a field. If options is set, the default form will be a selection box instead of a standard text box, and the options in this selection box are the options in options.

This is an example of the choices list:

YEAR_IN_SCHOOL_CHOICES = (
    ('FR', 'Freshman'),
    ('SO', 'Sophomore'),
    ('JR', 'Junior'),
    ('SR', 'Senior'),
    ('GR', 'Graduate'),
)

The first element in each tuple is the value stored in the database; The second element is the content used for display in the management interface or modelchoicefield. In a given model class instance, if you want to get the display value of a choices field, callget_FOO_displayMethod (here foo is the name of the choices field). For example:

from django.db import models

class Person(models.Model):
    SHIRT_SIZES = (
        ('S', 'Small'),
        ('M', 'Medium'),
        ('L', 'Large'),
    )
    name = models.CharField(max_length=60)
    shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES)
>>> p = Person(name="Fred Flintstone", shirt_size="L")
>>> p.save()
>>> p.shirt_size
'L'
>>> p.get_shirt_size_display()
'Large'

default

The default value of the field. It can be a value or a callable object. If it is callable, it will be called every time a new object is created.

help_text

Additional help content displayed by the form part. Even if the field is not used in the form, it is useful for generating documents.

primary_key

IfTrueThen this field is the primary key of the model.

If you don’t specify any of the fieldsprimary_key=TrueDjango will automatically add oneIntegerFieldFields are used as primary keys, so you don’t need to set any of the fields unless you want to override the default primary key behaviorprimary_key=True. See_ Auto increment primary key field_

The primary key field is read-only. If you change the value of the primary key on an existing object and save it, a new object will be created outside the original object. For example:

from django.db import models

class Fruit(models.Model):
    name = models.CharField(max_length=100, primary_key=True)
>>> fruit = Fruit.objects.create(name='Apple')
>>> fruit.name = 'Pear'
>>> fruit.save()
>>> Fruit.objects.values_list('name', flat=True)
['Apple', 'Pear']

unique

If the value is set toTrueThe value of this data field must be unique in the whole table

Again, these are just a brief introduction to common fields. For details, please refer to the general model field options reference(_common model field option reference_).

Auto increment primary key field

By default, Django adds the following field to each model:

id = models.AutoField(primary_key=True)

This is a self incrementing primary key field.

If you want to specify a custom primary key field, just specify it on a fieldprimary_key=TrueThat’s it. If Django sees that you explicitly set theField.primary_key, will not be added automaticallyidColumn.

Only one field can be specified per modelprimary_key=True(whether explicitly declared or automatically added).

The readme name of the field

exceptForeignKeyManyToManyFieldandOneToOneFieldIn addition, each field type accepts an optional positional parameter — the field’s readme name. If no readme is given, Django automatically creates a readme based on the field’s property name — replacing the underline of the property name with a space.

In this case, the readme is"person's first name":

first_name = models.CharField("person's first name", max_length=30)

In this case, the readme is  "first name"

first_name = models.CharField(max_length=30)

ForeignKeyManyToManyFieldandOneToOneFieldIt is required that the first parameter is a model class, so theverbose_nameKeyword parameter to specify the readme:

poll = models.ForeignKey(Poll, verbose_name="the related poll")
sites = models.ManyToManyField(Site, verbose_name="list of sites")
place = models.OneToOneField(Place, verbose_name="related place")

Traditionally,verbose_nameDon’t capitalize the first letter of. Django capitalizes automatically when necessary.

relationship

Obviously, the power of relational database lies in the correlation between tables. Django provides three most common database relationships: many to one, many to many, and one to one.

Many to one relationship

Django usedjango.db.models.ForeignKeyDefine many to one relationships. And use othersfieldType is the same: include it as a class attribute in the model.

ForeignKeyA positional parameter is required: the class associated with the model.

For example, a carCarThere is oneManufacturer——But oneManufacturerMake a lot of cars, every carCarThere can only be oneManufacturer——Use the following definition:

from django.db import models

class Manufacturer(models.Model):
    # ...
    pass

class Car(models.Model):
    manufacturer = models.ForeignKey(Manufacturer)
    # ...

You can also create_ The relation of recursion_(objects and themselves are associated many to one) and_ Association with an undefined model_; See_ Model field reference_

It is recommended that you use the lowercase name of the associated model as theForeignKeyThe name of the field (for example, above)manufacturer)。 Of course, you can have another name. For example:

class Car(models.Model):
    company_that_makes_it = models.ForeignKey(Manufacturer)
    # ...

See also

ForeignKeyField also takes many other parameters, which are_ Model field reference_There is a detailed introduction. These options help define how relationships should work; They are all optional parameters.

For details of accessing reverse association objects, see_Following relationships backward example_

For example code, see_ Example of many to one relationship model_)。

Many to many relationship

ManyToManyFieldUsed to define many to many relationships, usage, and moreFieldThe field type is the same: it is included as a class property in the model.

ManyToManyFieldA positional parameter is required: the class associated with the model.

For example, aPizzaThere can be manyTopping——AToppingIt can be on multiple pizzas, and eachPizzaThere are many kinds of topping as follows:

from django.db import models

class Topping(models.Model):
    # ...
    pass

class Pizza(models.Model):
    # ...
    toppings = models.ManyToManyField(Topping)

And useForeignKeyYou can also create_ The relation of recursion_(objects and their many to many associations) and_ Association with a model that has not yet defined a relationship_; See_ Model field reference_

It is recommended that you use the plural form of the name of the associated model as an exampleManyToManyFieldThe name of thetoppings)。

In which modelManyToManyFieldIt doesn’t matter, just choose one of the two models – don’t set both.

In general,ManyToManyFieldThe instance should be in a form that can be edited. In the example above,toppingsbe locatedPizzaIn (not in)ToppingIt’s set insidepizzasOfManyToManyFieldField), because it’s more natural to assume that a pizza has multiple toppings than a topping on multiple pizza. In the way above, in thePizzaUsers will be allowed to select different toppings in the form of.

See also

For a complete example, see_ Example of many to many relationship model_

ManyToManyFieldField also accepts other parameters_ Model field reference_It is described in detail in. These options help define how relationships should work; They are all optional.

Other fields in many to many relationships

When dealing with simple many to many relationships such as pairing with pizza and topping, standardManyToManyField  That’s it. However, sometimes you may need to relate the data to the relationship between the two models.

For example, there is an app that records the music group to which the musician belongs. We can use oneManyToManyFieldRepresents the many to many relationship between a group and its members. However, sometimes you may want to know more about the details of the membership, such as when the members joined the group.

In these cases, Django allows you to specify a model to define many to many relationships. You can put other fields in the mediation model. Source modelManyToManyFieldField will usethroughThe parameters point to the mediation model. For the above Music Group example, the code is as follows:

from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=128)

    def __str__(self):              # __unicode__ on Python 2
        return self.name

class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(Person, through='Membership')

    def __str__(self):              # __unicode__ on Python 2
        return self.name

class Membership(models.Model):
    person = models.ForeignKey(Person)
    group = models.ForeignKey(Group)
    date_joined = models.DateField()
    invite_reason = models.CharField(max_length=64)

When setting the mediation model, explicitly specify the foreign key and associate it with the model involved in many to many relationships. This explicit declaration defines how the two models relate.

The mediation model has some limitations:

  • The mediation model must_ There is and only one_ Foreign key to the source model (in the example above)Group), or you have to useManyToManyField.through_fieldsExplicitly specify the foreign key that Django should use. If there are more than one foreign key in your model, andthrough_fieldsIf not specified, an invalid error will be triggered. There are the same restrictions on the foreign keys of the target model (in the example above)Person)。

  • Two foreign keys to the same model are allowed to exist in the model of many to many association with itself through mediation model, but they will be regarded as two (different) aspects of many to many association. If so_ Over_ Two foreign keys. You must specify them as abovethrough_fieldsOtherwise, a validation error will be raised.

  • When you use the mediation model to define many to many relationships with yourself, you_ Must_ set upsymmetrical=False(see_ Model field reference_)。

Changed in Django 1.7:

In Django 1.6 and earlier, the mediation model prohibited more than one foreign key.

Now that you’ve set it upManyToManyFieldTo use the mediation model (in this case, theMembership)Next, you start creating many to many relationships. All you have to do is create an instance of the mediation model:

>>> ringo = Person.objects.create(name="Ringo Starr")
>>> paul = Person.objects.create(name="Paul McCartney")
>>> beatles = Group.objects.create(name="The Beatles")
>>> m1 = Membership(person=ringo, group=beatles,
...     date_joined=date(1962, 8, 16),
...     invite_reason="Needed a new drummer.")
>>> m1.save()
>>> beatles.members.all()
[<Person: Ringo Starr>]
>>> ringo.group_set.all()
[<Group: The Beatles>]
>>> m2 = Membership.objects.create(person=paul, group=beatles,
...     date_joined=date(1960, 8, 1),
...     invite_reason="Wanted to form a band.")
>>> beatles.members.all()
[<Person: Ringo Starr>, <Person: Paul McCartney>]

Unlike normal many to many fields, you can_ No_ useaddcreateAnd assignment statements (for example,beatles.members = [...])To create a relationship:

# THIS WILL NOT WORK
>>> beatles.members.add(john)
# NEITHER WILL THIS
>>> beatles.members.create(name="George Harrison")
# AND NEITHER WILL THIS
>>> beatles.members = [john, paul, ringo, george]

Why not? That’s because you can’t just createPersonandGroupYou also need to specify the relationship between themMembershipAll the information needed in the model; And simpleaddcreateAnd assignment statements can’t do that. So they cannot be used in many to many relationships that use the mediation model. At this point, the only way is to create an instance of the mediation model.

remove()Method is disabled for the same reason. howeverclear()  Methods are available. It can clear all the many to many relationships of an instance

>>> # Beatles have broken up
>>> beatles.members.clear()
>>> # Note that this deletes the intermediate model instances
>>> Membership.objects.all()
[]

After you create a many to many relationship by creating an instance of the mediation model, you can execute the query. Like many to many fields, you can directly use the attributes of the associated model to query

# Find all the groups with a member whose name starts with 'Paul'
>>> Group.objects.filter(members__name__startswith='Paul')
[<Group: The Beatles>]

If you use the mediation model, you can also use the properties of the mediation model to query

# Find all the members of the Beatles that joined after 1 Jan 1961
>>> Person.objects.filter(
...     group__name='The Beatles',
...     membership__date_joined__gt=date(1961,1,1))
[<Person: Ringo Starr]

If you need to access a member’s information, you can get it directlyMembershipModel:

>>> ringos_membership = Membership.objects.get(group=beatles, person=ringo)
>>> ringos_membership.date_joined
datetime.date(1962, 8, 16)
>>> ringos_membership.invite_reason
'Needed a new drummer.'

Another way to get the same information is in thePersonQuery on object_ Many to many inverse relation_

>>> ringos_membership = ringo.membership_set.get(group=beatles)
>>> ringos_membership.date_joined
datetime.date(1962, 8, 16)
>>> ringos_membership.invite_reason
'Needed a new drummer.'

One to one relationship

OneToOneFieldUsed to define a one-to-one relationship. Usage and othersfieldTypes are the same: they are included as class attributes in the model.

When an object wants to extend from another object, the most common way is to add a one-to-one relationship to the primary key of the object.

OneToOneFieldYou want a positional parameter: the class associated with the model.

For example, you want to build a “places” database with some common fields, such as address, phone number, etc. Next, if you want to build a restaurant database based on the place database, you don’t want to copy the existing fields to the place databaseRestaurantModel, then you canRestaurantAdd oneOneToOneFieldField, which points toPlace(because restaurant itself is a place; In fact, when dealing with this problem, you should use a typical_ Succession_It implies a one-to-one relationship.

And useForeignKeyAgain, you can define_ The relation of recursion_and_ Reference a model that has no defined relationship_. See_ Model field reference_

See also

stay_ An example of one to one relationship model_There is a complete set of examples in.

OneToOneFieldFields also accept a specific optionalparent_linkParameters, in_ Model field reference_It is described in detail in.

In previous versions,OneToOneFieldThe field automatically becomes the primary key of the model. But now it’s not (but you can still pass it if you want to)primary_keyParameter to create the primary key field. So there can be more than one in a modelOneToOneFieldField.

Cross file model

It’s very easy to access the models of other applications. At the top of the file where you define the model, import the relevant model to implement it. Then, you can refer to it wherever you need it. For example:

from django.db import models
from geography.models import ZipCode

class Restaurant(models.Model):
    # ...
    zip_code = models.ForeignKey(ZipCode)

Restrictions on field naming

Django has only two restrictions on field naming:

  1. The name of the field cannot be a python reserved keyword because this will result in a python syntax error. For example:

    class Example(models.Model):
        pass = models.IntegerField() # 'pass' is a reserved word!
    
  2. Because of the way the Django query syntax works, there cannot be more than one consecutive underline in a field name. For example:

    class Example(models.Model):
        foo__bar = models.IntegerField() # 'foo__bar' has two underscores!
    

These restrictions are flexible because there is no requirement that the field name must match the column name of the database. ginsengdb_columnOptions.

Reserved words of SQLjoinwhereandselect, which can be used as the field name of the model, because Django will escape the database table name and column name in the underlying SQL query statement. It uses different reference syntax based on your database engine.

Custom field type

If the existing model fields are not suitable, or you want to use the advantages of some rare database column types, you can create your own field types. Create your own fields in_ Write custom model fields_There is a complete story in.

Meta options

Use internalclass MetaDefine the metadata of the model, for example:

from django.db import models

class Ox(models.Model):
    horn_length = models.IntegerField()

    class Meta:
        ordering = ["horn_length"]
        verbose_name_plural = "oxen"

Model metadata is “any data that is not a field,” such as sorting options(ordering), data table name(db_table)Or human readable singular and plural names(verbose_nameandverbose_name_plural)。 Add to modelclass MetaIt is completely optional, and all options are not required.

AllelementA complete list of options can be found in_ Model options reference_Find it.

Properties of the model

objects

The most important attribute of a model is the
Manager. It’s the interface through which
database query operations are provided to Django models and is used to
_retrieve the instances_ from the database. If no
custom Manager is defined, the default name is
objects. Managers are only accessible via
model classes, not the model instances.

Methods of modeling

You can define custom methods on the model to add custom “bottom” functions to your objects.ManagerMethods are used for “table scope” transactions, and model methods should focus on specific model instances.

It’s a very valuable technology to put the business logic in the same place – the model.

For example, the following model has some custom methods:

from django.db import models

class Person(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    birth_date = models.DateField()

    def baby_boomer_status(self):
        "Returns the person's baby-boomer status."
        import datetime
        if self.birth_date < datetime.date(1945, 8, 1):
            return "Pre-boomer"
        elif self.birth_date < datetime.date(1965, 1, 1):
            return "Baby boomer"
        else:
            return "Post-boomer"

    def _get_full_name(self):
        "Returns the person's full name."
        return '%s %s' % (self.first_name, self.last_name)
    full_name = property(_get_full_name)

The last method in this example is a_property_

_ Model example reference_With a complete_ The method of automatic generation for model_List. You can cover them – see belowMethod of covering model predefined——But there are ways you’ll always want to redefine:

__str__() (Python 3)

Python 3 equivalent of __unicode__().

__unicode__() (Python 2)

A python “magic method” that returns the Unicode “Representation” of an object. Python and Django use this method when model instances need to be cast and displayed as normal strings. The most obvious is when an object is displayed in an interactive console or management site.

Will always want to define this method; The default method makes little sense.

get_absolute_url()

It tells Django how to calculate the URL of an object. Django uses this method in its administration site, as well as in any other case where you need to calculate the URL of an object.

Any object that has a URL that uniquely identifies itself should define this method.

Method of covering predefined models

There is another part that encapsulates the behavior of the database_ Model method_, you may want to customize them. In particular, you’re going to change a lotsave()anddelete()How they work.

You are free to override these methods (and any other modeling methods) to change their behavior.

A typical use scenario for overriding the built-in method is that you want to do something else when you save an object. For example (seesave()For the parameters it accepts in the

from django.db import models

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()

    def save(self, *args, **kwargs):
        do_something()
        super(Blog, self).save(*args, **kwargs) # Call the "real" save() method.
        do_something_else()

You can also prevent saving:

from django.db import models

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()

    def save(self, *args, **kwargs):
        if self.name == "Yoko Ono's blog":
            return # Yoko shall never have her own blog!
        else:
            super(Blog, self).save(*args, **kwargs) # Call the "real" save() method.

You have to remember to call the superclass method——super(Blog, self).save(*args, **kwargs)——To ensure that the object is saved to the database. If you forget to call this method of the superclass, the default behavior will not happen and the database will not change.

Also remember to pass parameters to the model method – that is, the*args, **kwargs. Django will always extend the function of built-in model method and add new parameters in the future. If used in your method definition*args, **kwargsWill ensure that your code automatically supports these new parameters.

Overridden model methods are not called on bulk operations

Attention, when_ When using query set to batch delete objects_, will not be called for each objectdelete()method. To ensure that the custom delete logic is executed, you can use thepre_deleteAnd / orpost_deleteSignal.

Unfortunately, when it comes to mass productioncreatingorupdatingObject, there is no workaround because it will not be calledsave()pre_saveandpost_save

Execute custom SQL

Another common requirement is to write custom SQL statements in model method and module level method. For more details on using the original SQL statement, see_ Use original SQL_Document for.

Model inheritance

Model inheritance in Django is almost the same as ordinary class inheritance in Python, but the basic requirements of the model listed in the head of this page should be followed. This means that the custom model class should inheritdjango.db.models.Model

The only decision you need to make is whether you want the parent model to have its own database tables, or whether you want the parent model to hold only some common information that can only be seen in the child model.

There are three styles of inheritance in Django.

  1. Usually, you just want to use the parent class to hold some information. You don’t want to type it in every submodel. This class will never be used alone, so you can use it_ Abstract base class_

  2. If you inherit an existing model and want each model to have its own database table, you should use_ Multi table inheritance_

  3. Finally, if you just want to change the python level behavior of the module without modifying the fields of the model, you can use the_ Proxy model_

Abstract base class

Abstract classes are very useful when you want to store some common information in many models. After you write the base class, in the_Meta_Classabstract=True, the class cannot create any tables. Instead, when it is used as a base class for other models, it will be added to that subclass. If the abstraction base class and its subclass have the same items, then error will appear (and Django will return an exception).

One example

from django.db import models

class CommonInfo(models.Model):
    name = models.CharField(max_length=100)
    age = models.PositiveIntegerField()

    class Meta:
        abstract = True

class Student(CommonInfo):
    home_group = models.CharField(max_length=5)

StudentThe model will have three items:name, ageandhome_groupCommonInfoThe model cannot be used like the general Django model because it is an abstract base class. It cannot generate data forms or managers, and cannot be instantiated or stored.

For many users, this type of model inheritance is what you want. It provides a way to extract common information at the python language level, but at the database level, each subclass still creates only one database.

elementinherit

When an abstract class is created, Django will automatically define the_Meta_As an attribute of a subclass. If the subclass does not declare its own_Meta_Class, which will inherit the_Meta_. if the subclass wants to extend the parent    Can inherit from the parent class  _Meta_  Yes, for example

from django.db import models

class CommonInfo(models.Model):
    # ...
    class Meta:
        abstract = True
        ordering = ['name']

class Student(CommonInfo):
    # ...
    class Meta(CommonInfo.Meta):
        db_table = 'student_info'

When inheriting, Django changes the base class_Meta_Class to make an adjustment: in the installation_Meta_Django sets theabstract=False. This means that subclasses of the abstract base class do not automatically become abstract classes. Of course, you can have an abstract class inherit another abstract base class, but explicitly set it every timeabstract=True

For an abstract base class, some properties are placed in the  _Meta_  There is no meaning in embedded classes. For example, includedb_tableWill mean all subclasses (those that do not specify themselves)_Meta_Class) use the same data table. Generally speaking, this is not what we want.

Use with carerelated_name

If you areForeignKeyOr  ManyToManyFieldField  related_nameProperty, you must always specify one for the field_ Only_ The reverse name of the. But doing so on an abstract base class raises a serious problem. Because Django will add base class fields to each subclass, and the field attribute values of each subclass are exactly the same (includingrelated_name)。

When you use in (and only in) abstract base classesrelated_nameIf you want to bypass this problem, you need to include'%(app_label)s'and  '%(class)s'

  • '%(class)s'Will be replaced with the lowercase underlined name of the subclass, and the field will be used in the subclass.

  • '%(app_label)s'Will be replaced with the lowercase underlined name of the application, which contains subclasses. The name of each installed application should be unique, and the name of each model class in the application should also be unique, so the generated names should be different from each other.

For example, suppose you have an app calledcommon/models.py

from django.db import models

class Base(models.Model):
    m2m = models.ManyToManyField(OtherModel, related_name="%(app_label)s_%(class)s_related")

    class Meta:
        abstract = True

class ChildA(Base):
    pass

class ChildB(Base):
    pass

And another applicationrare/models.py

from common.models import Base

class ChildB(Base):
    pass

The reverse name of the childa.m2m field is childa_ The reverse name of the childb.m2m field is childb_ related。 It depends on how you use it  '%(class)s'and'%(app_label)sTo construct your reverse name. If you don’t, Django will be verifying the model (or running it)migrate)An error is thrown when the.

If you don’t define an associated field in the abstract base classrelated_name  Property, then the default reverse name is the subclass name plus'_set'Whether it works depends on whether you define a field with the same name in a subclass. For example, in the above code, if you removerelated_nameProperties, inChildAIn the middle,m2mThe reverse name of the field ischilda_set; andChildBThe reverse name of the M2M field of ischildb_set

Multi table inheritance

This is the second inheritance supported by Django. When using this inheritance method, each sub model in the same level is a complete model in the true sense. Each submodel has its own data table, which can be queried and created. Inheritance adds a link (through an automatically createdOneToOneFieldTo achieve).   For example:

from django.db import models

class Place(models.Model):
    name = models.CharField(max_length=50)
    address = models.CharField(max_length=80)

class Restaurant(Place):
    serves_hot_dogs = models.BooleanField(default=False)
    serves_pizza = models.BooleanField(default=False)

PlaceAll the fields in it are in theRestaurantIs also valid, but the data is saved in another data table. So the following two statements can be run:

>>> Place.objects.filter(name="Bob's Cafe")
>>> Restaurant.objects.filter(name="Bob's Cafe")

If you have onePlace , So it’s also aRestaurantThen you can use the lowercase form of submodel from plPlaceObjectRestaurantParticipants:

>>> p = Place.objects.get(id=12)
# If p is a Restaurant object, this will give the child class:
>>> p.restaurant
<Restaurant: ...>

However, if thepAnd_ No_Restaurant ( For example, it’s justPlaceObject, or it is the parent of another class)p.restaurantIt will be thrown outRestaurant.DoesNotExistAbnormal.

On multi table inheritanceMeta

In multi table inheritance, the subclass inherits the_Meta_Classes are meaningless. be-all_Meta_  Option is already working on the parent class, and it’s only counterproductive to use it again( This is the opposite of using an abstract base class, because the abstract base class does not have its own content.)

So a child model does not have access to the_Meta_  Class. However, in some limited cases, a subclass can inherit some meta from its parent class: if the subclass does not specifyorderingProperty orget_latest_byProperties, it inherits them from the parent class.

If the parent class has sort settings and you don’t want the child class to have any sort settings, you can explicitly disable sort

class ChildModel(ParentModel):
    # ...
    class Meta:
        # Remove parent's ordering effect
        ordering = []

Inheritance and reverse association

Because multi table inheritance uses an implicitOneToOneFieldTo link a subclass to a parent, so as in the example above, you can use a parent to refer to a subclass. But this one to one field field is the defaultrelated_nameValue andForeignKeyandManyToManyField  The default reverse name is the same. If you do a many to one or many to many relationship with other subclasses of model, you canmustForce assignments on each many to one and many to many fieldsrelated_name. If you don’t, Django will run validation on you   An exception is thrown when.

For example, still abovePlaceClass, we create aManyToManyFieldSubclass of field:

class Supplier(Place):
    customers = models.ManyToManyField(Place)

This results in an error:

Reverse query name for 'Supplier.customers' clashes with reverse query
name for 'Supplier.place_ptr'.

HINT: Add or change a related_name argument to the definition for
'Supplier.customers' or 'Supplier.place_ptr'.

Like the following, tocustomersFieldrelated_nameYou can fix this error:models.ManyToManyField(Place, related_name='provider')

Specifies the field of the linked parent class

As we mentioned earlier, Django will automatically create oneOneToOneFieldField links the subclass to a non Abstract parent model. If you want to specify the property name of the link parent class, you can create your ownOneToOneFieldField and setparent_link=TrueTo use this field to link the parent class.

surrogate model

use  _ Multi table inheritance_Each subclass of the model creates a new data table, which is usually exactly what we want to do. This is because subclasses need a space to store field data that is not included in the base class. But sometimes, you may just want to change the behavior of the model in the python layer. For example, change the default manager or add a new method.

And that’s what the proxy model inheritance method does: create one for the original model_ Agency_  。 You can create, delete, and update instances of the proxy model, and all data can be saved as if you were using the original model. The difference is that you can change the default sort settings and the default manager in the proxy model without affecting the original model.

Declaring a proxy model is no different from declaring a normal model. set upMetaIn classproxy  The value of isTrueTo complete the declaration of the proxy model.

For example, suppose you want to give Django its own standardPersonModel adds a method. You can do this:

from django.db import models

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

class MyPerson(Person):
    class Meta:
        proxy = True

    def do_something(self):
        # ...
        pass

MyPersonClass and its parent classPerson  Operate on the same data table. In particular,Person  Any instance of theMyPersonVisit, and vice versa:

>>> p = Person.objects.create(first_name="foobar")
>>> MyPerson.objects.get(first_name="foobar")
<MyPerson: foobar>

You can also use the proxy model to define different default sorting settings for the model. You may not want to give it every timePersonModels are sorted, but agents are always used according to thelast_nameProperty sorting. It’s very easy:

class OrderedPerson(Person):
    class Meta:
        ordering = ["last_name"]
        proxy = True

Now, ordinaryPersonThe query is unordered, and  OrderedPersonThe inquiry will be made according to thelast_nameSort.

The query set always returns the requested model

That is to say, there is no way for Django to queryPersonObjectMyPersonObject.PersonObject’s query set returns objects of the same type. The point of proxy objects is that they rely on native objectsPersonObject’s code still uses it, and you can use the extension object you added (it doesn’t rely on any other code). It’s not going to bePersonModels (or other) are replaced everywhere with other models that you create yourself.

Restrictions on base classes

The proxy model must inherit from a non abstract base class. You cannot inherit from multiple non abstract base classes because a proxy model cannot connect to different tables. A proxy model can also inherit any number of abstract base classes, but only if they do_ No_   Define any model field.

Manager of agent model

If you do not define any managers in the proxy model, the proxy model inherits the managers from the parent class  。 If you define a manager in the agent model, it becomes the default manager  , However, the manager defined in the parent class is still valid.

Continue with the above example when you queryPersonWhen modeling, you can change the default manager, for example:

from django.db import models

class NewManager(models.Manager):
    # ...
    pass

class MyPerson(Person):
    objects = NewManager()

    class Meta:
        proxy = True

If you want to add a new manager to the agent instead of replacing the existing default manager, you can use the_ Custom manager_Create a base class with a new manager and inherit it after the main base class

# Create an abstract class for the new manager.
class ExtraManagers(models.Model):
    secondary = NewManager()

    class Meta:
        abstract = True

class MyPerson(Person, ExtraManagers):
    class Meta:
        proxy = True

You may not need to do this often, but it works.

Differences between proxy model and unmanaged model

Inheritance and use of proxy modelMetaIn classmanaged  The unmanaged model of the property is very similar. But the two are not the same, you should consider which option.

One difference is that you canMeta.managed=FalseIn fact, it must be specified unless you really want to get an empty model. Be careful when creating unmanaged modelsMeta.db_tableThis is because the unmanaged model created maps to an existing model and has its own method. Therefore, if you want to keep the two models synchronized and make changes to the program, it will become cumbersome and fragile.

Another difference is that they handle the manager differently. The behavior of the proxy model should be similar to that of the model it represents, so the proxy model should inherit the managers of the parent model, including its default manager. However, in common multi table inheritance, the subclass cannot inherit the manager of the parent class, because the manager of the parent class may not be applicable when dealing with non base class fields. In the latter case_ Manager document_There is a detailed introduction.

After we implemented these two features, we tried to combine them. The results show that the combination of macro inheritance and micro manager not only makes API complex and difficult to use, but also difficult to understand. As these two options may be needed in any situation, they are still used independently at present.

Therefore, the general rule is:

  1. If you want to learn from an existing model or data table, and do not want to involve all the columns of the original data table, then letMeta.managed=False. This option is usually used when creating models or tables for database views that do not need to be controlled by Django.

  2. If you want to make Python level changes to the model and keep the fields unchanged, you canMeta.proxy=True. Therefore, when the data is saved, the proxy model is equivalent to completely copying the storage structure of the original model.

multiple inheritance

Like Python subclasses, Django’s model can be inherited from multiple parent models. Remember that the general Python name resolution rules also apply. The first base class with a specific name (such as_Meta_)It’s the one used. For example, this means that if multiple parent classes contain  _Meta_Class, only the first one will be used, and the rest will be ignored.

In general, you don’t need to inherit multiple parent classes. Multiple inheritance is mainly useful for “mix in” classes: add a specific, extra field or method to each class that inherits mix in. You should try to keep your inheritance relationship as concise and direct as possible, so that you don’t have to work hard to figure out where a particular piece of information comes from.

Changed in Django 1.7\.

Before Django 1.7, inheriting multipleidThe model of primary key field will not throw an exception, but it will cause data loss. For example, consider these models (due toidFields, they are no longer valid:

class Article(models.Model):
    headline = models.CharField(max_length=50)
    body = models.TextField()

class Book(models.Model):
    title = models.CharField(max_length=50)

class BookReview(Book, Article):
    pass

This code shows how to create an object of a subclass and override the value in the parent object that was created earlier.

>>> article = Article.objects.create(headline='Some piece of news.')
>>> review = BookReview.objects.create(
...     headline='Review of Little Red Riding Hood.',
...     title='Little Red Riding Hood')
>>>
>>> assert Article.objects.get(pk=article.pk).headline == article.headline
Traceback (most recent call last):
  File "<console>", line 1, in <module>
AssertionError
>>> # the "Some piece of news." headline has been overwritten.
>>> Article.objects.get(pk=article.pk).headline
'Review of Little Red Riding Hood.'

You can use explicitAutoFieldTo use multiple inheritance properly:

class Article(models.Model):
    article_id = models.AutoField(primary_key=True)
    ...

class Book(models.Model):
    book_id = models.AutoField(primary_key=True)
    ...

class BookReview(Book, Article):
    pass

Or use a common ancestor to holdAutoField

class Piece(models.Model):
    pass

class Article(Piece):
    ...

class Book(Piece):
    ...

class BookReview(Book, Article):
    pass

Field name “hiding” is not permitted

Ordinary Python class inheritance allows subclasses to override any property of the parent class. But in Django, rewritingFieldInstances are not allowed (at least not yet). If there is one in the base classauthorField, you can’t create any subclass namedauthorField for.

Rewriting the fields of the parent class will cause a lot of trouble, such as initializing the instance (specified in theModel.__init__And serialization. Ordinary Python class inheritance mechanism can’t handle these features well. So Django’s inheritance mechanism is designed to be different from python, which is not arbitrary.

These restrictions are only for those used as attributesFieldInstance, not for Python properties, which can still be overridden. In Python’s view, the above restriction is only for the name of the field instance: if you manually specify the column name of the database, then in multiple inheritance, you can use the same column name in a subclass and an ancestor class( Because they use fields from two different data tables).

If you override a model field in any ancestor class, Django will throw itFieldErrorAbnormal.

See also

_The Models Reference_

Covers all the model related APIs including model fields, related
objects, and QuerySet.

translator:Django document collaborative translation teamOriginal text:Model syntax

This paper is based onCC BY-NC-SA 3.0Please keep the author’s signature and the source of the article.

Django document collaborative translation teamWe are short of staff. Interested friends can join us. It is totally public welfare. Communication group: 467338606.

Recommended Today

Implementation example of go operation etcd

etcdIt is an open-source, distributed key value pair data storage system, which provides shared configuration, service registration and discovery. This paper mainly introduces the installation and use of etcd. Etcdetcd introduction etcdIt is an open source and highly available distributed key value storage system developed with go language, which can be used to configure sharing […]