====== Pro Django ====== Book: Pro Django 2nd ed. Apress Try code: source $_env/bin/activate python manage.py shell >>> import xxx >>> def do_smt(xxx): ... ====== Django is Py ====== Base class from django.db import models class Contact(models.Model): name = models.CharField(max_length=255) email = models.EmailField() Attribute Classes (CharField) look here: vim refman_env/lib/python2.7/site-packages/django/db/models/fields/__init__.py ====== Models ====== ===== Setting Attributes on Models ===== Python provides useful tools for getting and setting attributes on objects without knowing the name in advance, but while getattr() and setattr() represent the standard way of accessing attributes on objects, one of Django’s hooks for model fields requires some additional handling. Django provides a class method, add_to_class(), on all of its models, which should be used as a substitute for setattr(). ===== Getting infomation about models - _meta===== ==== Class information ==== Consider a situation where a model may be subclassed without inheriting all the Django-specific model inheritance processing. This requires a bit of tweaking with metaclasses, but can prove useful for solving certain types of problems. When doing this, the __name__ and __module__ attributes will refer to the child class, rather than the actual model that sits underneath. * _meta.module_name: module where the object is defined. * _meta.object_name: name of the classes. ==== Field Definitions ==== Django uses the creation_counter technique described in Chapter 2 to keep track of the order of fields, so they can be placed inside a list for future reference. This list is stored in the fields attribute of the model’s _meta attribute. _meta.get_field('fname') to get single field by name. from django.utils.text import capfirst def get_values(instance): for field in instance._meta.fields: name = capfirst(field.verbose_name) value = getattr(instance, field.name) print('%s: %s' % (name, value)) class Product(models.Model): sku = models.CharField(max_length=8, verbose_name='SKU') name = models.CharField(max_length=255) price = models.DecimalField(max_digits=5, decimal_places=2) def __unicode__(self): return self.name >>> from django.utils.text import capfirst >>> for field in Product._meta.fields: ... print('%s: %s' % (capfirst(field.verbose_name), field.__class__)) ... ID: SKU: Name: Price: >>> Product._meta.get_field('name').__class__ === Primary Key Fields === Django provides another _meta attribute, pk, which contains the field object that will be used as the primary key for the model. This is also faster than iterating over all the fields, since pk is populated once, when the model is first processed. After all, Django needs to determine whether it needs to provide an implicit primary key. The _meta.pk attribute is also used to enable the pk shortcut property on model instances, which returns the primary key value for an instance, regardless of which field is the primary key. Django provides two attributes on the _meta attribute that help with this situation. The first, _meta.has_auto_field, is True if the model let Django provide an id field implicitly. If it’s False, the model has an explicit primary key, so Django didn’t have to intervene. The second attribute related to the automatic primary key field is _meta.auto_field, which will be the actual field object Django provided for use as the primary key. If _meta.has_auto_field is True, this will be an AutoField, and will always be configured the same way for all models that use it. It’s important to look at this attribute instead of making assumptions about the field’s structure, in case Django makes any changes in the future. It’s an easy way to help make sure your application keeps working properly in the future. If a model provides its own primary key field, and thus _meta.has_auto_field is False, _meta.auto_field will be set to None. === Configuration Options === abstract app_label db_table === Accessing the Model Cache === Once models have been processed by the ModelBase metaclass, they’re placed in a global registry called AppCache, located at django.db.models.loading. ==== Retrieving All Applications ==== The first step in a site-wide introspection is to determine what applications are installed. Calling cache.get_apps() will return such a list, containing the application module for each application in the INSTALLED_APPS setting that contains a models module. That’s not to say that it only returns applications that have models. It actually checks for the presence of a models module, so even an empty models.py will cause an application to be included in this list. Take, for example, the following INSTALLED_APPS setting, showing several of Django’s own contributed applications, as well as some in-house applications and the signedcookies application described in Chapter 7. INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', 'news', 'customers', 'callcenter', 'signedcookies', ) Most of these applications will, by necessity, contain various models. Chapter 7’s signedcookies, however, only interacts with the site’s HTTP traffic, so it has no use for the database. Therefore, when looking through the results of cache.get_apps(), the signedcookies application won’t show up. >>> from django.conf import settings >>> from django.db.models.loading import cache >>> len(settings.INSTALLED_APPS) 9 >>> len(cache.get_apps()) 8 >>> for app in cache.get_apps(): ... print(app.__name__) ... django.contrib.admin.models django.contrib.auth.models django.contrib.contenttypes.models django.contrib.sessions.models django.contrib.sites.models news.models customers.models callcenter.models ==== Retrieving a Single Application ==== Django provides a utility for handling this situation. By passing the known label to cache.get_app(), an application can retrieve the application module for just the application matching that particular label. The label referred to here is determined as a specific part of the application’s import path. Typically referenced as app_label, an application’s label is usually formed from the last part of the application module’s import path before the models portion. To illustrate a few examples, consider the following application labels, corresponding to the entries in the INSTALLED_APPS setting. admin auth contenttypes sessions sites news customers callcenter signedcookies As demonstrated earlier with cache.get_apps(), applications without models are viewed slightly differently within Django itself than others. By default, cache.get_app() will raise an ImproperlyConfigured exception if the application doesn’t contain a models.py file. Sometimes it may still be useful to process applications without models, so cache.get_app() accepts an optional second argument to control how such applications are handled. This second argument, called emptyOK, takes a Boolean indicating whether the application is allowed to not contain any models. This defaults to False, which will raise the ImproperlyConfigured exception, but if True is given instead, cache.get_app() will simply return None, allowing the calling code to continue managing the application. >>> from django.db.models.loading import cache >>> print(cache.get_app('admin')) >>> print(cache.get_app('signedcookies')) Traceback (most recent call last): ... django.core.exceptions.ImproperlyConfigured: App with label signedcookies could not be found >>> print(cache.get_app('signedcookies', emptyOK=True)) None ==== Dealing with Individual Models ==== In the first case, consider pure introspection. Remember from the previous section that AppCache provides access to all known applications with a single call to the get_apps() method, which returns application modules. Since these modules are actually the models modules within each application, it may seem easy to just use dir(app_module) or iterate over app_module.__dict__ to get the models that were defined. cache.get_models() retrieves a list of proper Django models that are specific to the given application module. It’s no coincidence that both cache.get_apps() and cache.get_app() return application modules; cache.get_models() is suitable for use with both of these methods. That means that a list of models can be retrieved even without an application, but knowing the application in advance reduces the number of models retrieved. The following code demonstrates how these techniques can be used in combination to retrieve a list of models for each of the known applications in use on the site. >>> from django.db.models.loading import cache >>> for app in cache.get_apps(): ... app_label = app.__name__.split('.')[-2] ... for model in cache.get_models(app): ... print('%s.%s' % (app_label, model.__name__)) ... admin.LogEntry auth.Message auth.Group auth.User auth.Permission contenttypes.ContentType sessions.Session sites.Site news.News customers.Customer callcenter.Agent callcenter.Call callcenter.Case As an additional option, get_models() can also be called with no argument, which will cause it to return all the models that are known to AppCache. This is a useful shortcut to avoid some of the overhead associated with the extra loop in this example, as a quick way to grab all the models. There’s a catch, however. When using get_models() directly, with no argument, all registered models are returned. This may sound like a great idea, and sometimes it is, but remember that AppCache registers all models as they’re encountered, regardless of where they were found. The full list may include models that aren’t part of an installed application. Contrast that with the get_apps()/get_models() combination, which only retrieves models if their applications are found in the INSTALLED_APPS setting. ===== Using Model Fields ===== ==== Common Fields Attributes ==== * attname * blank * choices: A sequence of 2-tuples indicating the valid choices for the field. The first item in each tuple is the actual value that would be stored in the database if selected, while the second item is the text that will be displayed to the user for that value. * column * db_column * db_index * db_tablespace * ... ==== Common Field Methods ==== * clean(value, instance) * contribute_to_class(cls, name) * ... ===== Subclassing Fields ===== ====== URLs and Views ======