
Good day!
Another part of a series of my translations of the
section on models from the
Django documentation .
')
Translation Django Documentation: Models. Part 1Translation Django Documentation: Models. Part 2___ Meta Parameters
___ Model methods
_____ Override predefined methods
_____ Using SQL
___ Inheritance of models
_____ Abstract base classes
_______ Meta Inheritance
_______ Be careful with related_names
Translation Django Documentation: Models. Part 4 (Last)Meta ParametersYou can add meta data to your model using the internal class
Meta :
Copy Source | Copy HTML<br/> class Ox (models.Model):<br/> horn_length = models.IntegerField()<br/> <br/> class Meta :<br/> ordering = [ "horn_length" ]<br/> verbose_name_plural = "oxen" <br/>
The meta data in the model is “something that is not a field,” for example: sorting parameters (
ordering ), database table name (
db_table ), readable names of objects in a single (
verbose_name ) or plural (
verbose_name_plural ) number and so on. Meta data is optional, adding a
Meta class to your model is completely optional.
A complete list of
meta- parameters can be found in the
help on model parameters .
Model methodsYou can define methods in the model to add your own functionality to your objects. While the
Manager methods are designed to work with data from the entire table, model methods are created for actions in a separate instance of the model.
This technique is useful for keeping the business logic of an application in one place - in a model.
For example, this model has several proprietary methods:
Copy Source | Copy HTML<br/> from django.contrib.localflavor.us.models import USStateField<br/> <br/> class Person (models.Model):<br/> first_name = models.CharField(max_length= 50 )<br/> last_name = models.CharField(max_length= 50 )<br/> birth_date = models.DateField()<br/> address = models.CharField(max_length= 100 )<br/> city = models.CharField(max_length= 50 )<br/> state = USStateField() # Yes, this is America-centric... <br/> <br/> def baby_boomer_status (self):<br/> "Returns the person's baby-boomer status." <br/> import datetime<br/> if datetime .date( 1945 , 8 , 1 ) <= self .birth_date <= datetime .date( 1964 , 12 , 31 ):<br/> return "Baby boomer" <br/> if self .birth_date < datetime .date( 1945 , 8 , 1 ):<br/> return "Pre-boomer" <br/> return "Post-boomer" <br/> <br/> def is_midwestern (self):<br/> "Returns True if this person is from the Midwest." <br/> return self .state in ( 'IL' , 'WI' , 'MI' , 'IN' , 'OH' , 'IA' , 'MO' )<br/> <br/> def _get_full_name (self):<br/> "Returns the person's full name." <br/> return '%s %s' % ( self .first_name, self .last_name)<br/> full_name = property ( _get_full_name ) <br/>
The final method in this example is a managed attribute (
property ). More details
here .
The
help for model instances contains a complete list of
automatically added methods for each model . You can override most of them (see below). There are also a couple of methods that override in most cases:
__unicode __ ()The "magic method" of the Python language, which returns the "representation" of any object in the unicode encoding. It is used when you want to display an instance of the model in the form of a simple, understandable line. For example, when working in an interactive console or in the administrator interface.
Redefinition of this method is required quite often, because the standard is not very useful.
get_absolute_url ()This method tells Django an algorithm for calculating the URL for an object. It is used in the administrator interface, as well as every time you need to find out the URL of a certain object.
Each object that has a uniquely identifiable URL must contain this method.
Override predefined methods
There are several more
model methods with which you can change the behavior of the database. In particular, it is often necessary to change the algorithm of the
save () and
delete () methods.
You can override these methods (as well as all the others in the model), and thereby change their behavior.
For example, the redefinition of built-in methods is used if you want some actions to be performed when saving an object (for more information about the parameters taken by the
save () method, see the
documentation ):
Copy Source | Copy HTML<br/> class Blog (models.Model):<br/> name = models.CharField(max_length= 100 )<br/> tagline = models.TextField()<br/> <br/> def save (self, force_insert=False, force_update=False):<br/> do_something()<br/> super ( Blog , self). save (force_insert, force_update) # The "real" save() method. <br/> do_something_else()
You can also prevent saving:
Copy Source | Copy HTML<br/> class Blog (models.Model):<br/> name = models.CharField(max_length= 100 )<br/> tagline = models.TextField()<br/> <br/> def save (self, force_isert=False, force_update=False):<br/> if self .name == "Yoko Ono's blog" :<br/> return # Yoko shall never have her own blog! <br/> else :<br/> super ( Blog , self). save (force_insert, force_update) # The "real" save() method. <br/>
It is important not to forget to call the method of the inherited class (in our example
super (Blog, self) .save () ), to ensure that the data is saved to the database. If you forget to call this method, the database will remain untouched.
Using SQL
Another commonly used technique is to write your own SQL constructs in model methods or module methods. For more information about using raw SQL you can read the
documentation .
Model inheritanceAdded in Django version 1.0 : please read the release notes .The principle of inheritance of models in Django is almost completely identical to the inheritance of classes in the Python language. The only decision you have to make is whether the inherited models will be a database table, or they will only be data keepers, and access to them will be possible only through derived models.
There are three types of inheritance in Django:
- Often, you need the base class to simply contain some information that you do not want to define in each derived model. Such a class will never be used as an independent unit, which means that the Abstract Base Classes will suit you best (as described below).
- If, when creating subclasses, you want each model to have its own table in the database, look towards Multi-tabular inheritance .
- Finally, if you want to change the behavior of a model at the Python level without changing its fields, use proxy models .
Abstract base classes
Abstract base classes are useful when you want to create several models with general information. Create a base class, put the parameter
abstract = True in the
Meta class, and this model will not be used when creating database tables. Instead, when it is used as the base for some model, its fields will be added to the derived class. If the field name in the base and derived class matches, Django will raise an exception.
Example:
Copy Source | Copy HTML<br/> class CommonInfo (models.Model):<br/> name = models.CharField(max_length= 100 )<br/> age = models.PositiveIntegerField()<br/> <br/> class Meta :<br/> abstract = True<br/> <br/> class Student ( CommonInfo ):<br/> home_group = models.CharField(max_length= 5 ) <br/>
The
Student model will contain three fields:
name, age, and
home_group . Since the
CommonInfo model is an abstract base class, it will not be used as a regular Django model: it will not generate a database table, have a
manager , cannot save or create its instance directly.
In many cases, this type of inheritance will meet your requirements. This method allows you to "put out" the general information at the Python level, while at the database level, separate tables will be created for each derived class.
Meta InheritanceWhen creating an abstract base class, Django makes the inner
Meta class that you define in the base class available as an attribute. If a derived class
Meta is not defined in the derived class, it will be inherited from the parent. However, if you wish, you can extend the base
Meta class by using inheritance in the
Meta classes. For example:
Copy Source | Copy HTML<br/> class CommonInfo (models.Model):<br/> ...<br/> class Meta :<br/> abstract = True<br/> ordering = [ 'name' ]<br/> <br/> class Student ( CommonInfo ):<br/> ...<br/> class Meta ( CommonInfo . Meta ):<br/> db_table = 'student_info' <br/>
Django makes only one adjustment in the
Meta class of the abstract base class: before setting the
Meta attribute, the
abstract parameter is set to
False . This is done so that derived classes do not automatically become abstract. Of course, you can create an abstract base class that inherits from another abstract base class. To do this, you just need to explicitly set
abstract = True .
It does not make sense to add some attributes to the
Meta class of the abstract base class. For example, adding the
db_name parameter will mean that all derived classes that do not have their own
Meta class will use the same database table. Almost certainly, this is not what you wanted.
Be careful with related_nameIf you use the
related_name attribute in the
ForeignKey or
ManyToManyField field , you must define a
unique reverse name for each field. This usually results in a problem in abstract base classes, since all fields and their values ​​are added to each derived class.
To get around this problem, when using the
related_name attribute in abstract base classes (and only in them), the string
'% (class) s' should be part of the name. It will be replaced with the name of the lower-class derived class in which this field is used. Since classes have different names, each attribute will have a unique value. For example:
Copy Source | Copy HTML<br/> class Base (models.Model):<br/> m2m = models.ManyToManyField(OtherModel, related_name= "%(class)s_related" )<br/> <br/> class Meta :<br/> abstract = True<br/> <br/> class ChildA ( Base ):<br/> pass <br/> <br/> class ChildB ( Base ):<br/> pass <br/>
The reverse name
ChildA.m2m will be
childa_related , and for
ChildB.m2m ,
childb_related . It’s up to you to use the
% (class) s construct, but if you forget about it, Django will throw an exception when validating your models (or
syncdb ).
If you did not define the
related_name attribute for a field in an abstract base class, the reverse name will by default be the name of a lowercase derived class with the addition of the
'_set' string, so that you explicitly define this field directly in the derived class. For example, for the text above, if the
related_name attribute were omitted, the return names for the m2m fields would be
childa_set for the
ChildA class and
childb_set in the case of the
ChildB class.
That's all for today :) The next part will be the last in this section. I think, after its translation, create a survey - whether Habra needs these same translations or not. Will I continue to depend on its results. In the meantime, you need to complete the translation of what started)
to be continuedAny comments are welcome :)
Translation Django Documentation: Models. Part 1Translation Django Documentation: Models. Part 2Translation Django Documentation: Models. Part 4 (Last)