.. .. META INFORMATION OF TRANSLATION .. .. $TranslationStatus: Done, waiting for revision. $ .. $OriginalRevision: 11268 $ .. $TranslationAuthors: Robson Mendonça $ .. .. INFO OF THIS FILE (DO NOT EDIT! UPDATED BY SUBVERSION) .. .. $HeadURL$ .. $LastChangedRevision$ .. $LastChangedBy$ .. $LastChangedDate$ .. .. _ref-contrib-contenttypes: ======================== O Framework contenttypes ======================== .. module:: django.contrib.contenttypes :synopsis: Provê uma interface genérica para models instalados. O Django incluí uma applicação :mod:`contenttypes` que pode mapear todos os modelos instalados no seu projeto feito com o Django, provendo uma interface genérica de auto-nível para trabalhar com seus models. Visão geral =========== O coração da aplicação contenttypes é o model :class:`~django.contrib.contenttypes.models.ContentType`, que reside em ``django.contrib.contenttypes.models.ContentType``. As instâncias de :class:`~django.contrib.contenttypes.models.ContentType` representam e armazenam informações sobre os models instalados no seu projeto, e novas instâncias de :class:`~django.contrib.contenttypes.models.ContentType` são automaticamente criadas quando um novos models são instalados. As instâncias do :class:`~django.contrib.contenttypes.models.ContentType` possuem métodos para retornar as classes de models que elas representam e para consultas de objetos para estes models. O :class:`~django.contrib.contenttypes.ContentType` também tem um :ref:`gerenciador customizado ` que adiciona métodos par trabalhar com :class:`~django.contrib.contenttypes.models.ContentType` e para obtenção de instâncias de :class:`~django.contrib.contenttypes.models.ContentType` para um model em particular. Os relacionamentos entre seus models e :class:`~django.contrib.contenttypes.models.ContentType` pode também ser usados para habilitar relacionamentos "genericos" entre uma instância de um de seus models e instâncias de qualquer model que você tenha instalado. Instalando o framework contenttypes =================================== O framework contenttypes vem incluído por padrão no :setting:`INSTALLED_APPS` quando é criado pelo ``django-admin.py startproject``, mas se você o tiver removido ou se você manualmente setou seu :setting:`INSTALLED_APPS`, você pode habilitá-lo adicionando ``'django.contrib.contenttypes'`` no :setting:`INSTALLED_APPS`. Geralmente é uma boa idéia ter o framework contenttypes instaldo; vários outras applicações nativas do Django necessitam dele: * A aplicação admin o usa para logar a história de cada objeto adicionado ou modificado através da interface de administração. * O :mod:`framework de autenticação ` do Django o usa para amarrar as permissões de usuários para models específicos. * O sistema de comentários do Django (:mod:`django.contrib.comments`) o usa para "atachar" comentário em qualquer model instalado. O model ``ContentType`` ======================= .. class:: models.ContentType Cada instância do :class:`~django.contrib.contenttypes.models.ContentType` possui três campos, que juntos, descrevem a unicidade de um model instalado: .. attribute:: models.ContentType.app_label O nome da applicação da qual o model faz parte. Este é o atributo :attr:`app_label` do model, e incluí somente a *última* parte do caminho de import do Python da aplicação; "django.contrib.contenttypes", por exemplo, tem um :attr:`app_label` "contenttypes". .. attribute:: models.ContentType.model O nome da classe do model. .. attribute:: models.ContentType.name O nome, legível por humanos, do model. Este é o atributo :attr:`verbose_name ` do model. Vamos olhar um exemplo, para entender como isso funciona. Se você já tem a aplicação contenttypes instalada, e adicionou :mod:`a aplicação sites ` no :setting:`INSTALLED_APPS` e executou o ``manage.py syncdb`` para instalá-lo, o model :class:`django.contrib.sites.models.Site` será instalado dentro do seu banco de dados. Imediatamente uma nova instância de :class:`~django.contrib.contenttypes.models.ContentType` será criada com os seguintes valores: * :attr:`app_label` será setado como ``'sites'`` (a última parte do caminho Python "django.contrib.sites"). * :attr:`model` será setada como ``'site'``. * :attr:`name` será setada como ``'site'``. .. _o atributo verbose_name: ../model-api/#verbose_name Métodos das instâncias do ``ContentType`` ========================================= .. class:: models.ContentType Cada instância :class:`~django.contrib.contenttypes.models.ContentType` possui métodos que permitem você pegar através da instância do :class:`~django.contrib.contenttypes.models.ContentType` o model que ela representa, ou receber objetos daquele model: .. method:: models.ContentType.get_object_for_this_type(**kwargs) Pega um conjunto de :ref:`argumentos aparentes ` válidos para o model que :class:`~django.contrib.contenttypes.models.ContentType` representa, e faz :ref:`um get() lookup ` sobre este model, retornando o objeto correspondente. .. method:: models.ContentType.model_class() Retorna a classe de model representada por esta instância de :class:`~django.contrib.contenttypes.models.ContentType`. Por exemplo, nós podemos procurar no :class:`~django.contrib.contenttypes.models.ContentType` pelo model :class:`~django.contrib.contenttypes.models.User`:: >>> from django.contrib.contenttypes.models import ContentType >>> user_type = ContentType.objects.get(app_label="auth", model="user") >>> user_type E então usá-lo para pesquisar por um ``User`` particular, ou para ter acesso a classe model do ``User``:: >>> user_type.model_class() >>> user_type.get_object_for_this_type(username='Guido') Juntos, :meth:`~django.contrib.contenttypes.models.ContentType.get_object_for_this_type` e :meth:`~django.contrib.contenttypes.models.contenttypes.model_class` habilitam dois casos extremamente importantes: 1. Usando estes métodos, você pode escrever código genérico de auto-nível que faz consultas sobre qualquer model instalado -- ao invés de importar e usar uma classe de model específica, você passar um ``app_label`` e ``model`` dentro de um :class:`~django.contrib.contenttypes.models.ContentType` em tempo de execução, e então trabalhar com a classe model ou receber objetos dela. 2. Você pode relacionar outro model com :class:`~django.contrib.contenttypes.models.ContentType` como uma forma de vinculá-lo a determinadas classes de model, e usar estes métodos para acessar essas classes. Várias aplicações nativas do Django fazem uso desta última técnica. Por exemplo, :class:`o sistema de permissões no framework de autenticação usa um model :class:`~django.contrib.auth.models.Permission` com uma chave estrangeira para :class:`~django.contrib.contenttypes.models.ContentType`; isso permite que o :class:`~django.contrib.contenttypes.models.Permission` represente conceitos como "pode adicionar entrada no blog" ou "pode apagar notícia". O ``ContentTypeManager`` ------------------------ .. class:: models.ContentTypeManager O :class:`~django.contrib.contenttypes.models.ContentType` também tem um gerenciador personalizado, :class:`~django.contrib.contenttypes.models.ContentTypeManager`, que adiciona os seguintes métodos: .. method:: models.ContentTypeManager.clear_cache() Limpa um cache interno usado por instâncias do :class:`~django.contrib.contenttypes.models.ContentType`. Você provavelmente nunca precisará chamar este método você mesmo; O Django o chamará automaticamente quando for necessário. .. method:: models.ContentTypeManager.get_for_model(model) Pega ambos, um model ou uma instância de um model, e retorna a instância :class:`~django.contrib.contenttypes.models.ContentType` representando aquele model. O método :meth:`~models.ContentTypeManager.get_for_model()` e especialmente usual quando você sabe que precisa trabalhar com um :class:`ContentType ` mas não quer ter o trabalho de obter os metadados do model para executar um lookup manual:: >>> from django.contrib.auth.models import User >>> user_type = ContentType.objects.get_for_model(User) >>> user_type .. _generic-relations: Relações genéricas ================== Adicionando uma chave estrangeira em um de seus models para :class:`~django.contrib.contenttypes.models.ContentType` permite seu model vincular-se efetivamente em outro model, como no exemplo da classe :class:`~django.contrib.auth.modes.Permission` acima. Mas isto é possível ir além e usar :class:`~django.contrib.contenttypes.models.ContentType` para habilitar um relacionamento verdadeiramente genérico (algumas vezes chamado "polimórfico") entre os models. Um simples exemplo é um sistema de tags, que pode parecer com isto:: from django.db import models from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes import generic class TaggedItem(models.Model): tag = models.SlugField() content_type = models.ForeignKey(ContentType) object_id = models.PositiveIntegerField() content_object = generic.GenericForeignKey('content_type', 'object_id') def __unicode__(self): return self.tag Uma :class:`~django.db.models.fields.related.ForeignKey` normal pode somente "apontar para" um outro model, que significa que se o model ``TaggedItem`` usou uma :class:`~django.db.models.fields.related.ForeignKey` ele teria de escolher somente um model para armazenar as tags. A aplicação contenttypes provê um tipo de campo especial -- :class:`django.contrib.contenttypes.generic.GenericForeignKey` -- que funciona contornando isto e permitindo o relacionamento ser feito com qualquer model. Há três configurações para uma :class:`~django.contrib.contenttypes.generic.GenericForeignKey`: 1. Dê a seu model uma :class:`~django.db.models.fields.related.ForeignKey` para :class:`~django.contrib.contenttypes.models.ContentType`. 2. Dê a seu model um campo que consiga armazenar um valor de chave primária dos models que você irá relacionar. (Para maioria dos models, isto significa um :class:`~django.db.models.fields.IntegerField` ou :class:`~django.db.models.fields.PositiveIntegerField`.) Este campo deve ser do mesmo tipo da chave primária dos models envolvidos no relacionamento genérico. Por exemplo, se você usa :class:`~django.db.models.fields.IntegerField`, você não será capaz de formar uma relação genérica com um model que utiliza um :class:`~django.db.models.fields.CharField` como uma chave primária. 3. Dê a seu model uma :class:`~django.contrib.contenttypes.generic.GenericForeignKey`, e passe os nomes dos campos descritos acima para ela. Se estes campos são nomeados "content_type" e "object_id", você pode omitir isto -- estes são nomes padrão dos campos que :class:`~django.contrib.contenttypes.generic.GenericForeignKey` irá procurar. Isto habilitará uma API similar a que é usada por uma :class:`~django.db.models.fields.related.ForeignKey` normal; cada ``TaggedItem`` terá um campo ``content_type`` que retorna o objeto ao qual está relacionado, e você pode também atribuir ao campo ou usá-lo quando estiver criando uma ``TaggedItem``:: >>> from django.contrib.auth.models import User >>> guido = User.objects.get(username='Guido') >>> t = TaggedItem(content_object=guido, tag='bdfl') >>> t.save() >>> t.content_object Devido a forma como o :class:`~django.contrib.contenttypes.generic.GenericForeignKey` é implementado, você não pode usar campos estes campos diretamente com filtros (``filter()`` e ``exclude()``, por exemplo) via API de banco de dados. Eles não são campos normal de objetos. Estes exemplos *não* irão funcionar:: # Isto falhará >>> TaggedItem.objects.filter(content_object=guido) # Isto também falhará >>> TaggedItem.objects.get(content_object=guido) Reverso de relações genéricas ----------------------------- Se você sabe quais models serão usados com mais frequência, você pode também adicionar um "reverso" de relações genéricas para habilitar uma API adicional. Por exemplo:: class Bookmark(models.Model): url = models.URLField() tags = generic.GenericRelation(TaggedItem) Cada instância ``Bookmark`` terá um atributo ``tags``, que pode ser usado para receber seus ``TaggedItems`` associados:: >>> b = Bookmark(url='http://www.djangoproject.com/') >>> b.save() >>> t1 = TaggedItem(content_object=b, tag='django') >>> t1.save() >>> t2 = TaggedItem(content_object=b, tag='python') >>> t2.save() >>> b.tags.all() [, ] Assim como :class:`django.contrib.contenttypes.generic.GenericForeignKey` aceita os nomes dos campos content-type e object-ID como argumentos, para construir uma ``GenericRelation``; se o model que possui a chave estrangeira genérica está usando nomes diferentes do padrão, para estes campos, você deve passar os nomes dos campos quando estiver configurando uma ``GenericRelation``. Por exemplo, se o model ``TaggedItem`` referido acima usasse campos com nomes ``content_type_fk`` e ``object_primary_key`` para criar suas chaves primárias genéricas, então uma ``GenericRelation`` teria de ser definida como:: tags = generic.GenericRelation(TaggedItem, content_type_field='content_type_fk', object_id_field='object_primary_key') É claro, Se você não adicionar o reverso de relacionamento, você pode fazer os mesmos tipo de busca manualmente:: >>> b = Bookmark.objects.get(url='http://www.djangoproject.com/') >>> bookmark_type = ContentType.objects.get_for_model(b) >>> TaggedItem.objects.filter(content_type__pk=bookmark_type.id, ... object_id=b.id) [, ] Note que se o model com uma :class:`~django.contrib.contenttypes.generic.GenericForeignKey` que você está referenciando usa um valor diferente do padrão para ``ct_field`` ou ``fk_field`` (e.g. a aplicação :mod:`django.contrib.comments` usa ``ct_field="object_pk"``), você precisará passar ``content_type_field`` e ``object_id_field`` para :class:`~django.contrib.contenttypes.generic.GenericRelation`.:: comments = generic.GenericRelation(Comment, content_type_field="content_type", object_id_field="object_pk") Note que se você deleta um objeto que tem uma :class:`~django.contrib.contenttypes.generic.GenericRelation`, quaisquer objetos que possuem uma :class:`~django.contrib.contenttypes.generic.GenericForeignKey` apontando para ele, serão deletados também. No exemplo acima, isto significa que se um objeto ``Bookmark`` foi deletado, qualquer objeto ``TaggedItem`` relacionado com ele, será deletado ao mesmo tempo. Relacionamentos genéricos em formulários e admin ------------------------------------------------ O :mod:`django.contrib.contenttypes.generic` provê ambos, :class:`~django.contrib.contenttypes.generic.GenericInlineFormSet` e :class:`~django.contrib.contenttypes.generic.GenericInlineModelAdmin`. Isso permite o uso de relacionamentos genéricos nos formulários e no admin. Veja a documentação do :ref:`model formset ` e :doc:`admin ` para mais informações. .. class:: generic.GenericInlineModelAdmin A classe :class:`~django.contrib.contenttypes.generic.GenericInlineModelAdmin` herda todas as propriedades da classe :class:`~django.contrib.admin.options.InlineModelAdmin`. No entanto, ela adiciona alguns próprios para funcionar com relacionamento genérico. .. attribute:: generic.GenericInlineModelAdmin.ct_field O nome do campo chave estrangeira :class:`~django.contrib.contenttypes.models.ContentType` para o model. O padrão é ``content_type``. .. attribute:: generic.GenericInlineModelAdmin.ct_fk_field O nome do campo inteiro que representa o ID do objeto relacionado. O padrão é ``object_id``.