O Django é usado em um estilo maravilhosamente modular; é simples para substituir os diferentes componentes de um aplicativo Django baseado na web. Como os bancos de dados NoSQL são mais comuns nos dias de hoje, pode ser que você queira tentar executar um aplicativo com um backend diferente, em vez de um dos bancos de dados relacionais padrão, como o MySQL®. Neste artigo, você começa a saborear o MongoDB, incluindo como chamá-lo em seus projetos Python usando o PyMongo ou o MongoEngine. Logo, você usa o Django e o MongoEngine para criar um blog simples que pode executar operações Create, Read, Update, and Delete (CRUD).
Sobre os bancos de dados NoSQL
De acordo com o nosql-database.org, os bancos de dados NoSQL são a "próxima geração de bancos de dados endereçando primordialmente alguns dos pontos: ser não relacional, distribuído, software livre e escalável horizontalmente". Nesta classe de banco de dados está o MongoDB, um banco de dados orientado a documento.
Na prática do dia a dia, o Django 1.3 inclui suporte ao SQLite, MySQL, PostgreSQL e Oracle, mas não inclui suporte ao MongoDB. No entanto, é fácil incluir suporte ao MongoDB. Infelizmente, a desvantagem é que você perde o painel de administração automática. Portanto, você tem que pesar isso com relação às suas necessidades.
O MongoDB age como um interpretador de JavaScript e, portanto, a manipulação do banco de dados é feita por meio de comandos JavaScript. Depois de instalá-lo localmente na sua máquina (consulte Recursos), tente alguns dos comandos mostrados em Listagem 1.
Lista 1. Comandos JavaScript de amostra que podem ser testados com o MongoDB
var x = "0";
x === 0;
typeof({});
|
Não é necessário ser um especialista em JavaScript para começar a usar o MongoDB, ainda assim, seguem alguns conceitos úteis:
- É possível criar objetos usando a sintaxe literal de objeto, em outras palavras,
com duas chaves (por exemplo
var myCollection = {};). - É possível criar matrizes com colchetes
(
[]). - Tudo no JavaScript é um objeto, exceto para números, variáveis booleanas, nulo e indefinido.
Se você quiser saber mais sobre outros recursos do JavaScript, como a programação orientada a objetos de protótipo (OOP), regras de escopo e a sua natureza de programação funcional, consulte Recursos.
O MongoDB não possui esquemas, contrastando com os bancos de dados relacionais. Em vez de tabelas, coleções, que consistem em documentos, são usadas. Os documentos são criados usando sintaxe literal de objeto, conforme mostrado na Listagem 2.
Lista 2. Exemplos de criação de documento
var person1 = {name:"John Doe", age:25};
var person2 = {name:"Jane Doe", age:26, dept: 115};
|
Agora, execute os comandos mostrados na Listagem 3 para criar uma nova coleção.
Lista 3. Criando coleções
db.employees.save(person1); db.employees.save(person2); |
Como o MongoDB não possui esquemas, person1 e
person2 não precisam ter os mesmos tipos de coluna,
ou até o mesmo número de colunas. Além disso, o MongoDB é dinâmico por natureza,
por isso cria funcionários ao invés de lançar um erro. É possível
recuperar documentos por meio do método find() . Para obter todos os documentos em funcionários, chame
find() sem qualquer argumento, conforme mostrado na Listagem 4.
Lista 4. Uma consulta MongoDB simples
> db.employees.find();
// returns
[
{ "_id" : { "$oid" : "4e363c4dcc93747e68055fa1" },
"name" : "John Doe", "age" : 25 },
{ "_id" : { "$oid" : "4e363c53cc93747e68055fa2" },
"name" : "Jane Doe", "dept" : 115, "age" : 26 }
]
|
Observe que _id é o equivalente a uma chave
primária. Para executar consultas específicas, é necessário passar outro objeto com o par de chave/valor
que indica o que você está consultando, conforme mostrado na Listagem 5.
Lista 5. Consulta por um parâmetro de pesquisa
> db.employees.find({name: "John Doe"});
// returns
[
{ "_id" : { "$oid" : "4e363c4dcc93747e68055fa1" },
"name" : "John Doe", "age" : 25 }
]
|
Para consultar os funcionários com idade acima de 25 anos, execute o comando mostrado na Listagem 6.
Lista 6. Consulta pelos funcionários com idade superior a 25 anos
> db.employees.find({age:{'$gt':25}});
// returns
[
{ "_id" : { "$oid" : "4e363c53cc93747e68055fa2" },
"name" : "Jane Doe", "dept" : 115, "age" : 26 }
]
|
O $gt é um operador especial que significa maior
do que. A Tabela 1 lista alguns outros modificadores.
Tablela 1. Os modificadores que podem ser usados com o MongoDB
| Modificador | Descrição |
|---|---|
| $gt | Maior que |
| $lt | Menor que |
| $gte | Maior ou igual a |
| $lte | Menor ou igual a |
| $in | Verificar a existência de um array, semelhante ao operador
'in' de SQL. |
É possível, evidentemente, atualizar um registro usando o método
update() . É possível atualizar todo o
registro, conforme mostrado na Listagem 7.
Lista 7. Atualizar um registro todo
> db.employees.update({
name:"John Doe", // Document to update
{name:"John Doe", age:27} // updated document
});
|
Como alternativa, é possível atualizar apenas um único valor usando o operador
$set , conforme mostrado na Listagem 8 .
Lista 8. Atualizar um valor único em um registro
> db.employees.update({name:"John Doe",
{ '$set': {age:27} }
});
|
Para esvaziar uma coleção, chame o método remove()
sem qualquer argumento. Por exemplo, se deseja remover o "John Doe" da coleção funcionários,
você poderia fazer o que é mostrado na Listagem 9.
Lista 9. Remover o "John Doe" da coleção de funcionários
> db.employees.remove({"name":"John Doe"});
> db.employees.find();
// returns
[
{ "_id" : { "$oid" : "4e363c53cc93747e68055fa2" }, "name" : "Jane Doe",
"dept" : 115, "age" : 26 }
]
|
Isso é apenas o suficiente para você começar. Claro que você pode continuar explorando o site oficial, que possui um prompt de comando mongodb interativo e puro baseado na web completo com tutorial, bem como os documentos oficiais. Consulte Recursos.
Integrando o Django ao MongoDB
Você tem algumas opções de acesso ao MongoDB a partir do Python ou Django. A primeira é usar o módulo Python, PyMongo. Listagem 10 é uma sessão PyMongo de amostra, supondo que você tenha instalado o MongoDB e já tenha uma instância rodando em uma porta.
Lista 10. Sessão de PyMongo de amostra
from pymongo import Connection
databaseName = "sample_database"
connection = Connection()
db = connection[databaseName]
employees = db['employees']
person1 = { "name" : "John Doe",
"age" : 25, "dept": 101, "languages":["English","German","Japanese"] }
person2 = { "name" : "Jane Doe",
"age" : 27, "languages":["English","Spanish","French"] }
print "clearing"
employees.remove()
print "saving"
employees.save(person1)
employees.save(person2)
print "searching"
for e in employees.find():
print e["name"] + " " + unicode(e["languages"])
|
O PyMongo permite que você execute mais de um banco de dados simultaneamente. Para definir uma
conexão, basta passar em um nome de banco de dados para uma instância de conexão.
Os dicionários Python, neste caso, substituem os literais de objeto JavaScript
para criar novas definições de documentos, e as listas de
Python substituem matrizes de JavaScript. O método find
retorna um objeto cursor de banco de dados sobre o qual é possível iterar.
A semelhança na sintaxe facilita a alternância entre a linha de comando MongoDB e a execução de comandos com PyMongo. Por exemplo, a Listagem 11 mostra como executar uma consulta com o PyMongo.
Lista 11. Executar uma consulta com o PyMongo
for e in employees.find({"name":"John Doe"}):
print e
|
A sua outra opção para chamar o MongoDB a partir do Python é o MongoEngine, que deve ser familiar caso você já tenha usado o ORM integrado do Django. O MongoEngine é um mapeador de documento para objeto, que é semelhante, em conceito, a um ORM. Listagem 12 mostra uma sessão de exemplo com o MongoEngine.
Lista 12. Sessão de exemplo do MongoEngine
from mongoengine import *
connect('employeeDB')
class Employee(Document):
name = StringField(max_length=50)
age = IntField(required=False)
john = Employee(name="John Doe", age=25)
john.save()
jane = Employee(name="Jane Doe", age=27)
jane.save()
for e in Employee.objects.all():
print e["id"], e["name"], e["age"]
|
O objeto Employee recebe herança de
mongoengine.Document. Neste exemplo, dois tipos de campo são usados: StringField e
IntField. Assim como o ORM do Django, para consultar
todos os documentos na coleção, você chama o
Employee.objects.all(). Observe que para acessar o ID
de objeto único, usa-se o "id" em vez de "_id".
Agora, um blog simples chamado Blongo será criado. O Python 1.7,
Django 1.3, MongoDB 1.8.2, MongoEngine 0.4 e Hypertext Markup Language
(HTML) 5 serão usados. Se deseja recriar minhas configurações exatas, eu usei o Ubuntu Linux
com o FireFox. O Blongo exibe qualquer entrada de blog inserida no carregamento da página
e permite a atualização e exclusão de qualquer entrada —em outras palavras,
todas as operações CRUD padrão. As visualizações do Django possuem três métodos:
index, update e o
delete.
As definições em Cascading Style Sheets (CSS) seguem em um arquivo estático separado. Não entrarei em detalhes aqui, mas fique à vontade para explorar o código fonte incluso em Download.
Considerando que tudo esteja instalado e funcionando bem, crie um novo projeto Django e os componentes necessários, conforme mostrado na Listagem 13.
Lista 13. Comandos para configuração do projeto de blog Django
$ django-admin.py startproject blongo $ cd blongo $ django-admin.py startapp blogapp $ mkdir templates $ cd blogapp $ mkdir static |
Como novidade para o Django 1.3, há um aplicativo contribuído incluso para uma melhor manipulação de arquivos estáticos. Ao incluir um diretório estático a qualquer diretório do aplicativo (como blogapp, neste caso) e certificar-se de que o django.contrib.staticfiles esteja incluído nos aplicativos instalados, o Django é capaz de localizar arquivos estáticos, como arquivos .css e .js, sem a necessidade de quaisquer ajustes adicionais. A Listagem 14 mostra as linhas dos arquivos de configuração que foram alteradas (a partir do arquivo settings.py padrão) para obter o aplicativo de blog em execução.
Lista 14. Linhas dos arquivos de configuração que foram alteradas (a partir do arquivo settings.py padrão)
# Django settings for blog project.
import os
APP_DIR = os.path.dirname( globals()['__file__'] )
DBNAME = 'blog'
TEMPLATE_DIRS = (
os.path.join( APP_DIR, 'templates' )
)
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
'blog.blogapp',
)
|
Você possui três modelos neste projeto: index.html, update.html e delete.html. A Listagem 15 mostra o código para todos os três arquivos de modelo.
Lista 15. Código para os arquivos de modelo index.html, update.html e delete.html
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<link href="{{STATIC_URL}}blog.css" rel="stylesheet" type="text/css">
</head>
<body>
<h1>Blongo</h1>
<form method="post" action="http://127.0.0.1:8000/">
{% csrf_token %}
<ul>
<li>
<input type="text" name="title" placeholder="Post Title" required>
</li>
<li>
<textarea name="content" placeholder="Enter Content" rows=5 cols=50 required>
</textarea>
</li>
<li>
<input type="submit" value="Add Post">
</li>
</ul>
</form>
<!-- Cycle through entries -->
{% for post in Posts %}
<h2> {{ post.title }} </h2>
<p>{{ post.last_update }}</p>
<p>{{ post.content }}</p>
<form method="get" action="http://127.0.0.1:8000/update">
<input type="hidden" name="id" value="{{ post.id }}">
<input type="hidden" name="title" value="{{ post.title }}">
<input type="hidden" name="last_update" value="{{ post.last_update }}">
<input type="hidden" name="content" value="{{ post.content }}">
<input type="submit" name="" value="update">
</form>
<form method="get" action="http://127.0.0.1:8000/delete">
<input type="hidden" name="id" value="{{post.id}}">
<input type="submit" value="delete">
</form>
{% endfor %}
</body>
</html>
<!-- update.html -->
<!DOCTYPE html>
<html>
<head>
<link href="{{STATIC_URL}}blog.css" rel="stylesheet" type="text/css">
</head>
<body>
<h1>Blongo - Update Entry</h1>
<form method="post" action="http://127.0.0.1:8000/update/">
{% csrf_token %}
<ul>
<li><input type="hidden" name="id" value="{{post.id}}"></li>
<li>
<input type="text" name="title" placeholder="Post Title"
value="{{post.title}}" required>
<input type="text" name="last_update"
value="{{post.last_update}}" required>
</li>
<li>
<textarea name="content" placeholder="Enter Content"
rows=5 cols=50 required>
{{post.content}}
</textarea>
</li>
<li>
<input type="submit" value="Save Changes">
</li>
</ul>
</form>
</body>
</html>
<!-- delete.html -->
<!DOCTYPE html>
<html>
<head>
<link href="{{STATIC_URL}}blog.css" rel="stylesheet" type="text/css">
</head>
<body>
<h1>Blongo - Delete Entry</h1>
<form method="post" action="http://127.0.0.1:8000/delete/">
{% csrf_token %}
<input type="hidden" name="id" value="{{id}}">
<p>Are you sure you want to delete this post?</p>
<input type="submit" value="Delete">
</form>
</body>
</html>
|
Em seguida, altere os mapeamentos de URL para o código mostrado na Listagem 16, que aponta para as visualizações para o índice, atualização e exclusão. Se você deseja que o blog de amostra crie novas entradas de blog (no índice), atualize as postagens de blog existentes e as exclua quando desejar. Cada ação é realizada pela postagem para uma URL específica.
Lista 16. Mapeamentos de URL para índice, atualização e exclusão
from django.conf.urls.defaults import patterns, include, url
urlpatterns = patterns('',
url(r'^$', 'blog.blogapp.views.index'),
url(r'^update/', 'blog.blogapp.views.update'),
url(r'^delete/', 'blog.blogapp.views.delete'),
)
|
Observe que não é necessário executar o comando
syncdb do Django. Para integrar o MongoDB
ao seu aplicativo, é necessário o MongoEngine. No arquivo models.py do
diretório blogapp, inclua o código mostrado na Listagem 17 .
Lista 17. Incluindo MongoEngine na camada de dados
from mongoengine import *
from blog.settings import DBNAME
connect(DBNAME)
class Post(Document):
title = StringField(max_length=120, required=True)
content = StringField(max_length=500, required=True)
last_update = DateTimeField(required=True)
|
O nome do banco de dados é obtido a partir do arquivo de definições para separar os interesses.
Cada postagem do Blog contém três campos obrigatórios:
title, content e o
last_update. Se você comparar e contrastar esta
listagem com o que você faria normalmente no Django, a diferença não será
enorme. Em vez de ter uma classe que herda do
django.db.models.Model, esta listagem usa a classe
mongoengine.Document em seu lugar. A diferença entre os tipos de dados não será detalhada aqui, mas sinta-se
a vontade para verificar os documentos do MongoEngine (consulte Recursos).
Tabela 2 lista os tipos de campo MongoEngine e mostra o tipo de campo Django ORM equivalente, se houver.
Tablela 2. Tipos de campo MongoEngine e Django ORM equivalentes
| Tipo de campo MongoEngine | Django ORM equivalente |
|---|---|
| StringField | CharField |
| URLField | URLField |
| EmailField | EmailField |
| IntField | IntegerField |
| FloatField | FloatField |
| DecimalField | DecimalField |
| BooleanField | BooleanField |
| DateTimeField | DateTimeField |
| EmbeddedDocumentField | Nenhum |
| DictField | Nenhum |
| ListField | Nenhum |
| SortedListField | Nenhum |
| BinaryField | Nenhum |
| ObjectIdField | Nenhum |
| FileField | FileField |
Finalmente, é possível configurar as suas visualizações. Seguem três métodos de visualização:
index, update e o
delete. Para executar a ação desejada, deve ser feita uma
solicitação de postagem para a URL específica. Por exemplo, para atualizar
um documento deve ser feita uma postagem para localhost:8000/update. Executar uma solicitação http
'GET' não salvará, atualizará e assim por diante. As novas postagens do blog são
inseridas a partir da visualização de índice. Listagem 18 mostra as
implementações para as visualizações de índice, atualização e exclusão.
Lista 18. As visualizações do Django
from django.shortcuts import render_to_response
from django.template import RequestContext
from models import Post
import datetime
def index(request):
if request.method == 'POST':
# save new post
title = request.POST['title']
content = request.POST['content']
post = Post(title=title)
post.last_update = datetime.datetime.now()
post.content = content
post.save()
# Get all posts from DB
posts = Post.objects
return render_to_response('index.html', {'Posts': posts},
context_instance=RequestContext(request))
def update(request):
id = eval("request." + request.method + "['id']")
post = Post.objects(id=id)[0]
if request.method == 'POST':
# update field values and save to mongo
post.title = request.POST['title']
post.last_update = datetime.datetime.now()
post.content = request.POST['content']
post.save()
template = 'index.html'
params = {'Posts': Post.objects}
elif request.method == 'GET':
template = 'update.html'
params = {'post':post}
return render_to_response(template, params, context_instance=RequestContext(request))
def delete(request):
id = eval("request." + request.method + "['id']")
if request.method == 'POST':
post = Post.objects(id=id)[0]
post.delete()
template = 'index.html'
params = {'Posts': Post.objects}
elif request.method == 'GET':
template = 'delete.html'
params = { 'id': id }
return render_to_response(template, params, context_instance=RequestContext(request))
|
Você deve ter notado as instruções eval usadas
para recuperar os IDs do documento. Isso é usado para evitar a necessidade de gravar a instrução
if mostrada na Listagem 19.
Lista 19. Forma alternativa de recuperar o ID do documento
if request.method == 'POST':
id = request.POST['id']
elif request.method == 'GET':
id = request.GET['id']
|
Também é possível escrever dessa maneira. Isso é tudo o que preciso para ter um blog simples ativo e funcionando. Obviamente, faltam muitos componentes para um produto final, tais como usuários, um login, tags e assim por diante.
Como você pode ver, não há realmente muito para chamar o MongoDB a partir do Django. Neste artigo, apresentei rapidamente o MongoDB e expliquei como acessá-lo e manipular suas coleções e documentos a partir do Python por meio do wrapper PyMongo e o mapeador de objeto para documento MongoEngine. Finalmente, ofereci uma rápida demonstração de como criar um formulário CRUD básico usando o Django. Embora esta seja apenas a primeira etapa, espero que você entenda agora como aplicar esta configuração em seus próprios projetos.
| Descrição | Nome | Tamanho | Método de download |
|---|---|---|---|
| Sample Django application with MongoEngine | blongo.zip | 12KB | HTTP |
Informações sobre métodos de download
Aprender
- Saiba mais sobre o JavaScript por meio do tutorial do
Mozilla: "Uma reintrodução ao JavaScript," e pelo livro de Douglas Crockford:
JavaScript:
The Good Parts (O'Reilly Media/Yahoo Press, maio de 2008).
- Nos zona de software livre, encontre muitas informações de uso, ferramentas e atualizações de projetos
para ajudá-lo a desenvolver tecnologias de software livre e usá-las
com produtos IBM.
- Fique por dentro doseventos e webcasts técnicos do developerWorks com foco em uma variedade de produtos IBM e tópicos do segmento de mercado de TI.
- Participe de um briefing ao vivo e gratuito
do developerWorks para atualizar-se rapidamente sobre produtos e ferramentas IBM e tendências do segmento de mercado de TI.
- Siga o DeveloperWorks no Twitter.
- Acompanhe as Demos do developerWorks que abrangem desde demos de instalação e configuração de produtos para iniciantes até funcionalidade avançada para desenvolvedores experientes.
Obter produtos e tecnologias
- Saiba mais e faça o download do MongoDB.
- Faça o download e
explore o Django.
- Visite o website Python para obter os downloads e a documentação.
- Confira MongoEngine.
- Aprofunde-se em PyMongo.
-
Avalie produtos IBM da maneira que for melhor para você: faça download da versão de avaliação de um produto, avalie um produto on-line, use-o em um ambiente de nuvem ou passe algumas horas na SOA Sandbox aprendendo a implementar Arquitetura Orientada a Serviços de forma eficiente.
Discutir
- Participe da comunidade do developerWorks.
Entre em contato com outros usuários do developerWorks, enquanto explora os blogs, fóruns, grupos e wikis orientados ao desenvolvedor.
