Академический Документы
Профессиональный Документы
Культура Документы
Esse tutorial tem como objetivo explicar o bsico sobre Class Based Views no Django. Por motivos
de agilidade vou usar CBV para me referir as Class Based Views.
Segundo a documentao do Django sobre CBV:
CBV's permitem voc estruturar as suas views e reutilizar cdigo aproveitando heranas e mixins
O Django j vem CBV's genricas que atendem as necessidades da maioria das aplicaes. Essas
views genricas so flexiveis o suficiente para voc poder adapt-las as suas necessidades.
Nesse tutorial eu vou falar brevemente sobre os 4 grupos de CBV's que existem no Django
atualmente:
Base views
View
TemplateView
RedirectView
Display views
DetailView
ListView
Editing views
Model based Views
CreateView, UpdateView, DeleteView
Date views
ArchiveView
YearView
MonthView
WeekView
DayView
TodayView
DateDetailView
Concluso
Referncias
Antes de comearmos a falar sobre as CBV's vamos ver como apontar uma rota do Django para
uma CBV:
from django.conf.urls import url
from django.views.generic import TemplateView
from meuapp.views import AboutView
urlpatterns = [
url(r'^about/', AboutView.as_view()),
]
Base Views
As classes listadas abaixo contm muito da funcionalidade necessria para criar views no Django.
Essas classes so a base sob a qual as outras CBV's so construdas.
View
A classe genrica master. Todas as outras classes herdam dessa classe. O fluxo bsico de execuo
dessa classe quando recebe uma requisio :
1. dispatch()
2. http_method_not_allowed()
3. options()
A funo dispatch() verifica se a classe tem um mtodo com o nome do verbo HTTP usado na
requisio. Caso no haja, um http.HttpResponseNotAllowed retornado.
Essa classe sempre responde a requisies com o verbo OPTIONS retornando nesse caso uma lista
com os verbos suportados. A no ser que o mtodo options() seja sobrescrito.
Um exemplo de implementao:
from django.http import HttpResponse
from django.views.generic import View
class MyView(View):
def get(self, request, *args, **kwargs):
return HttpResponse('Hello, World!')
No exemplo acima a classe s responde a requisies do tipo GET e OPTIONS, todas as outras
requisies retornam http.HttpResponseNotAllowed.
Template View
Renderiza um template. O fluxo bsico de execuo dessa classe quando recebe uma requisio :
1. dispatch()
2. http_method_not_allowed()
3. get_context_data()
Quando voc precisa apenas renderizar uma pgina para o usurio essa com certeza a melhor
CBV para o caso. Voc pode editar o contexto que o template recebe sobrescrevendo a funo
get_context_data()
Um exemplo de implementao:
from django.views.generic.base import TemplateView
from articles.models import Article
class HomePageView(TemplateView):
template_name = "home.html"
No exemplo acima o template home.html ser renderizado e vai receber como contexto uma
varivel chamada lastest_articles.
Uma coisa interessante que o contexto da TemplateView populado pelo ContextMixin esse
mixin pega automaticamente os argumentos da URL que serviu a View.
Considere por exemplo:
from django.conf.urls import patterns, url
from .views import HelloView
urlpatterns = patterns(
'',
url(r'^say_hello/(?P<name>[\w_-]+)/$', HelloView.as_view(),
name='say_hello'),
)
No caso do exemplo acima o template renderizado pela HelloView teria em seu contexto a
varivel name.
Redirect View
Redireciona o usurio para a url informada.
A URL a ser redirecionada pode conter parmetros no estilo dicionrio-de-strings. Os parmetros
capturados na URL do RedirectView sero repassados para a URL que o usurio est sendo
redirecionado.
O fluxo bsico de execuo dessa classe quando recebe uma requisio :
1. dispatch()
2. http_method_not_allowed()
3. get_redirect_url()
Considere a seguinte configurao de URL's para o exemplo de implementao:
from django.conf.urls import url
from django.views.generic.base import RedirectView
from article.views import ArticleCounterRedirectView, ArticleDetail
urlpatterns = [
url(r'^counter/(?P<pk>[0-9]+)/$', ArticleCounterRedirectView.as_view(),
name='article-counter'),
url(r'^details/(?P<pk>[0-9]+)/$', ArticleDetail.as_view(), name='articledetail'),
]
Exemplo de implementao:
from django.shortcuts import get_object_or_404
from django.views.generic.base import RedirectView
Principais atributos:
url: A URL destino no formato de String
pattern_name: O nome do padro de URL. Um reverse ser aplicado usando os
mesmos args e kwargs passados para a RedirectView
permanent: Se for True retorna o status code como 301, caso contrrio, retorna 302.
query_string: Se for True a query_string ser enviada para a URL de destino.
Display Views
As duas views abaixo foram desenvolvidas para exibir informaes. Tipicamente essas views so as
mais usadas na maioria dos projetos.
DetailView
Renderiza um template contendo em seu contexto um objeto obtido pelo parmetro enviado na
URL.
No fluxo de execuo dessa view o objeto que est sendo utilizado est em self.object
O fluxo bsico de execuo dessa classe quando recebe uma requisio :
1. dispatch()
2. http_method_not_allowed()
3. get_template_names()
4. get_slug_field()
5. get_queryset()
6. get_object()
7. get_context_object_name()
8. get_context_data()
9. get()
10.render_to_response()
O fluxo parece grande e complexo mas na verdade muito simples e facilmente customizvel.
Basicamente o que acontece :
get_template_names() retorna uma lista de templates que devem ser usados para renderizar
a resposta. Caso o primeiro template da lista no seja encontrado o Django tenta o segundo e assim
por diante.
Em seguida o get_slug_field() entra em ao, essa funo deve retornar o nome do campo
que ser usado para fazer a busca pelo objeto. Por default o Django procura pelo campo slug.
Agora o get_queryset deve retornar um queryset que ser usado para buscar um objeto. Aqui
um timo lugar para, por exemplo, aplicar um filtro para exibir somente o Artigo cujo autor o
usurio logado. Considere o exemplo abaixo:
def ArtigoView(DetailView):
model = Artigo
get_queryset(self):
return self.model.filter(user=request.user)
# ... o restante do cdigo foi suprimido
get_queryset(self):
return self.model.filter(user=self.request.user)
urls.py
from django.conf.urls import url
from article.views import ArticleDetailView
urlpatterns = [
url(r'^(?P<titulo>[-\w]+)/$', ArticleDetailView.as_view(), name='articledetail'),
]
detalhe_artigo.html
<h1>{{ meu_artigo.titulo }}</h1>
<p>{{ meu_artigo.conteudo }}</p>
<p>Reporter: {{ meu_artigo.user.name }}</p>
<p>Published: {{ meu_artigo.data_publicacao|date }}</p>
ListView
Uma pgina que representa uma lista de objetos. Enquanto essa view est executando a varivel
self.object_list vai conter a lista de objetos que a view est utilizando.
O fluxo bsico de execuo dessa classe quando recebe uma requisio :
1.
2.
3.
4.
5.
6.
7.
8.
9.
dispatch()
http_method_not_allowed()
get_template_names()
get_queryset()
get_object()
get_context_object_name()
get_context_data()
get()
render_to_response()
Nada de novo aqui certo? Podemos exibir apenas uma lista de Artigos que esto com
status='publicado'
from django.views.generic.list import ListView
from django.utils import timezone
from articles.models import Artigo
class ArticleListView(ListView):
model = Artigo
def get_queryset(self, **kwargs):
return Artigo.objects.filter(status='publicado')
artigo_list.html
<h1>Articles</h1>
<ul>
{% for article in object_list %}
<li>{{ article.pub_date|date }} - {{ article.headline }}</li>
{% empty %}
<li>No articles yet.</li>
{% endfor %}
</ul>
Editing Views
As views descritas abaixo contm o comportamento bsico para edio de contedo.
FormView
Uma view que mostra um formulrio. Se houver erro, mostra o formulrio novamente contendo os
erros de validao. Em caso de sucesso redireciona o usurio para uma nova URL.
forms.py
from django import forms
class ContactForm(forms.Form):
name = forms.CharField()
message = forms.CharField(widget=forms.Textarea)
def send_email(self):
# send email using the self.cleaned_data dictionary
pass
views.py
from myapp.forms import ContactForm
from django.views.generic.edit import FormView
class ContactView(FormView):
template_name = 'contact.html'
form_class = ContactForm
success_url = '/thanks/'
def form_valid(self, form):
# This method is called when valid form data has been POSTed.
# It should return an HttpResponse.
form.send_email()
return super(ContactView, self).form_valid(form)
contact.html
<form action="" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Send message" />
</form>
views.py
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.core.urlresolvers import reverse_lazy
from myapp.models import Author
class AuthorCreate(CreateView):
model = Author
fields = ['name']
class AuthorUpdate(UpdateView):
model = Author
fields = ['name']
class AuthorDelete(DeleteView):
model = Author
success_url = reverse_lazy('author-list')
urls.py
from django.conf.urls import url
from myapp.views import AuthorCreate, AuthorUpdate, AuthorDelete
urlpatterns = [
# ...
url(r'author/add/$', AuthorCreate.as_view(), name='author_add'),
url(r'author/(?P<pk>[0-9]+)/$', AuthorUpdate.as_view(),
name='author_update'),
url(r'author/(?P<pk>[0-9]+)/delete/$', AuthorDelete.as_view(),
name='author_delete'),
]
O atributo fields determina quais campos do model devem estar presentes no formulrio.
obrigatrio especificar o atributo fields ou ento o atributo form_class, nunca os dois ao
mesmo tempo, pois isso geraria uma exceo ImproperlyConfigured.
importante notar tambm que a DeleteView exibe as informaes do objeto que ser deletado
quando acessada usando o verbo GET, quando usado o verbo POST o objeto efetivamente
apagado.
DICA: O nome dos templates determinado da seguinte forma:
Date Views
Date-based generic views so views com a funo de exibir pginas com dados filtrados por datas,
por exemplo: posts em um blog, notcias, consultas ao mdico, etc.
ArchiveIndexView
Uma pgina que exibe os "ltimas" objetos inseridos, desconsiderando aqueles com uma data futura
a no ser que o atributo allow_future seja definido como True.
importante notar que:
O nome default do context_object_name latest.
O sufixo _archive no nome do template.
Alm da lista de objetos o contexto tambm contem a varivel date_list contendo todos
os anos que tem objetos em ordem decrescente. Isso pode ser alterado para ms ou dia
usando o atributo date_list_period. Isso se aplica a todas as Data-based generic
views.
Implementao simples:
urls.py
from django.conf.urls import url
from django.views.generic.dates import ArchiveIndexView
from myapp.models import Article
urlpatterns = [
url(r'^archive/$',
ArchiveIndexView.as_view(model=Article, date_field="pub_date"),
name="article_archive"),
]
YearArchiveView
Uma pgina para exibir um arquivo anual. Retorna todos os objetos de um determinado ano.
No contexto alm da lista de objetos temos ainda:
date_list: Um objeto QuerySet contendo todos os meses que tenham objetos naquele
ano representados como objetos datetime.datetime em ordem crescente.
year: Um objeto datetime.datetime representando o ano atual
next_year: Um objeto datetime.datetime representando o prximo ano
previous_year: Um objeto datetime.datetime representando o ano anterior
Exemplo de implementao:
views.py
from django.views.generic.dates import YearArchiveView
urls.py
from django.conf.urls import url
from myapp.views import ArticleYearArchiveView
urlpatterns = [
url(r'^(?P<year>[0-9]{4})/$',
ArticleYearArchiveView.as_view(),
name="article_year_archive"),
]
article_archive_year.html
<ul>
{% for date in date_list %}
<li>{{ date|date }}</li>
{% endfor %}
</ul>
MonthArchiveView
Uma pgina para exibir um arquivo mensal. Retorna todos os objetos de um determinado ms.
No contexto alm da lista de objetos temos ainda:
date_list: Um objeto QuerySet contendo todos os dias que tenham objetos naquele ms
representados como objetos datetime.datetime em ordem crescente.
month: Um objeto datetime.datetime representando o ms atual
next_month: Um objeto datetime.datetime representando o prximo ms
previous_month: Um objeto datetime.datetime representando o ms anterior
Exemplo de implementao:
views.py
from django.views.generic.dates import MonthArchiveView
from myapp.models import Article
class ArticleMonthArchiveView(MonthArchiveView):
queryset = Article.objects.all()
date_field = "pub_date"
allow_future = True
urls.py
from django.conf.urls import url
from myapp.views import ArticleMonthArchiveView
urlpatterns = [
# Example: /2012/aug/
url(r'^(?P<year>[0-9]{4})/(?P<month>[-\w]+)/$',
ArticleMonthArchiveView.as_view(),
name="archive_month"),
# Example: /2012/08/
url(r'^(?P<year>[0-9]{4})/(?P<month>[0-9]+)/$',
ArticleMonthArchiveView.as_view(month_format='%m'),
name="archive_month_numeric"),
]
article_archive_month.html
<ul>
{% for article in object_list %}
<li>{{ article.pub_date|date:"F j, Y" }}: {{ article.title }}</li>
{% endfor %}
</ul>
<p>
{% if previous_month %}
Previous Month: {{ previous_month|date:"F Y" }}
{% endif %}
{% if next_month %}
Next Month: {{ next_month|date:"F Y" }}
{% endif %}
</p>
WeekArchiveView
Uma pgina para exibir um arquivo semanal. Retorna todos os objetos de uma determinada semana.
No contexto alm da lista de objetos temos ainda:
week: Um objeto datetime.datetime representando a semana atual
next_week: Um objeto datetime.datetime representando a prxima semana
previous_week: Um objeto datetime.datetime representando a semana anterior
Implementao simples:
views.py
from django.views.generic.dates import WeekArchiveView
from myapp.models import Article
class ArticleWeekArchiveView(WeekArchiveView):
queryset = Article.objects.all()
date_field = "pub_date"
week_format = "%W"
allow_future = True
urls.py
from django.conf.urls import url
from myapp.views import ArticleWeekArchiveView
urlpatterns = [
# Example: /2012/week/23/
url(r'^(?P<year>[0-9]{4})/week/(?P<week>[0-9]+)/$',
ArticleWeekArchiveView.as_view(),
name="archive_week"),
article_archive_week.html
<h1>Week {{ week|date:'W' }}</h1>
<ul>
{% if previous_week %}
Previous Week: {{ previous_week|date:"F Y" }}
{% endif %}
{% if previous_week and next_week %}--{% endif %}
{% if next_week %}
Next week: {{ next_week|date:"F Y" }}
{% endif %}
</p>
DayArchiveView
Uma pgina para exibir um arquivo dirio. Retorna todos os objetos de um determinado dia.
No contexto alm da lista de objetos temos ainda:
Implementao simples:
views.py
from django.views.generic.dates import DayArchiveView
from myapp.models import Article
class ArticleDayArchiveView(DayArchiveView):
queryset = Article.objects.all()
date_field = "pub_date"
allow_future = True
urls.py
from django.conf.urls import url
from myapp.views import ArticleDayArchiveView
urlpatterns = [
# Example: /2012/nov/10/
url(r'^(?P<year>[0-9]{4})/(?P<month>[-\w]+)/(?P<day>[0-9]+)/$',
ArticleDayArchiveView.as_view(),
name="archive_day"),
article_archive_day.html
<h1>{{ day }}</h1>
<ul>
{% if previous_day %}
Previous Day: {{ previous_day }}
{% endif %}
{% if previous_day and next_day %}--{% endif %}
{% if next_day %}
Next Day: {{ next_day }}
{% endif %}
</p>
TodayArchiveView
a mesma coisa do DayArchiveView mas no usa os parmetros da URL para determinar o
ano/ms/dia.
O que muda o urls.py, veja o exemplo abaixo:
from django.conf.urls import url
from myapp.views import ArticleTodayArchiveView
urlpatterns = [
url(r'^today/$',
ArticleTodayArchiveView.as_view(),
name="archive_today"),
]
DateDetailView
a mesma coisa que a DetailView com a diferena que a data utilizada junto com o pk/slug
para determinar qual objeto deve ser obtido.
O que muda o urls.py, veja o exemplo abaixo:
from django.conf.urls import url
from django.views.generic.dates import DateDetailView
urlpatterns = [
url(r'^(?P<year>[0-9]{4})/(?P<month>[-\w]+)/(?P<day>[0-9]+)/(?P<pk>[0-9]+)/
$',
DateDetailView.as_view(model=Article, date_field="pub_date"),
name="archive_date_detail"),
]
Concluso
Longe de tentar exaurir um assunto de tamanha complexidade e abrangncia minha inteno com
esse artigo foi mostrar o funcionamento bsico das Class Based Views e quem sabe incentivar voc
a utilizar CBV's no seu prximo projeto.
Envie para mim qualquer dvida, crtica ou sugesto que voc tiver em qualquer uma das minhas
redes sociais, posso demorar um pouco a responder mas eu respondo! :)
Comeando do comeo
Importante: estamos usando Django 1.8 e Python 3.
Criando o projeto
Eu usei este Makefile para criar o projeto.
wget --output-document=Makefile https://goo.gl/UMTpZ1
make setup
Ele vai criar um virtualenv e pedir pra voc executar os seguintes comandos:
source venv/bin/activate
cd djangoproject
make install
Pronto! Agora ns j temos um projetinho Django funcionando. Note que o nome da app core.
Criando as pastas
Para criarmos um novo comando precisamos das seguintes pastas:
core
management
__init__.py
commands
__init__.py
novocomando.py
No nosso caso, teremos 3 novos comandos, ento digite, estando na pasta djangoproject
mkdir -p core/management/commands
touch core/management/__init__.py
touch core/management/commands/{__init__.py,hello.py,initdata.py,search.py}
hello.py
from django.core.management.base import BaseCommand, CommandError
# minimalista
class Command(BaseCommand):
help = 'Print hello world'
def handle(self, **options):
self.stdout.write('Hello World')
Uso
$ python manage.py hello
initdata.py
Objetivo: Obter alguns filmes de uma api e salvar os dados no banco.
api: omdbapi.com
models.py
from django.db import models
class Movie(models.Model):
title = models.CharField(u'ttulo', max_length=100)
year = models.PositiveIntegerField('ano', null=True, blank=True)
released = models.CharField(u'lanamento', max_length=100, default='',
blank=True)
director = models.CharField('diretor', max_length=100, default='',
blank=True)
actors = models.CharField('atores', max_length=100, default='', blank=True)
poster = models.URLField('poster', null=True, blank=True)
imdbRating = models.DecimalField(max_digits=6, decimal_places=2, null=True,
blank=True)
imdbID = models.CharField(max_length=50, default='', blank=True)
class Meta:
ordering = ['title']
verbose_name = 'filme'
verbose_name_plural = 'filmes'
def __str__(self):
return self.title
No se esquea de fazer
python manage.py makemigrations
python manage.py migrate
admin.py
Vamos visualizar pelo admin.
from django.contrib import admin
from core.models import Movie
admin.site.register(Movie)
Instale o requests
pip install requests
initdata.py
O cdigo a seguir longo, mas basicamente temos
print_red(name) funo que imprime um texto em vermelho (opcional)
get_html(year) funo que l os dados da api usando requests, e depois escolhe um
filme randomicamente a partir de 2 letras
get_movie(year) se o dicionrio conter {'Response': 'True', ...} ento
retorna um dicionrio do filme localizado
save() salva os dados no banco
handle(movies, year) este o comando principal. Busca os filmes vrias vezes,
conforme definido pela varivel movies, e salva os n filmes.
# -*- coding: utf-8 -*- #
import random
import string
import requests
from django.core.management.base import BaseCommand, CommandError
from django.core.exceptions import ValidationError
from optparse import make_option
from core.models import Movie
class Command(BaseCommand):
help = """Faz o crawler numa api de filmes e retorna os dados.
Uso: python manage.py initdata
ou: python manage.py initdata -m 20
ou: python manage.py initdata -m 20 -y 2015"""
option_list = BaseCommand.option_list + (
make_option('--movies', '-m',
dest='movies',
default=10,
help='Define a quantidade de filmes a ser inserido.'),
make_option('--year', '-y',
dest='year',
action='store',
default=None,
help='Define o ano de lanamento do filme.'),
)
def print_red(self, name):
"""imprime em vermelho"""
print("\033[91m {}\033[00m".format(name))
def get_html(self, year):
"""
Le os dados na api http://www.omdbapi.com/ de forma aleatoria
e escolhe um filme buscando por 2 letras
"""
# Escolhe duas letras aleatoriamente
letters = ''.join(random.choice(string.ascii_lowercase) for _ in
range(2))
# Se no for definido o ano, ento escolhe um randomicamente
if year is None:
year = str(random.randint(1950, 2015))
url = 'http://www.omdbapi.com/?
t={letters}*&y={year}&plot=short&r=json'.format(letters=letters, year=str(year))
return requests.get(url).json()
def get_movie(self, year, **kwargs):
""" Retorna um dicionrio do filme """
movie = self.get_html(year)
j = 1 # contador
# Faz a validao de Response. Se a resposta for falsa, ento busca
outro filme.
while movie['Response'] == 'False' and j < 100:
movie = self.get_html(year)
self.print_red('Tentanto %d vezes\n' % j)
j += 1
return movie
def save(self, **kwargs):
"""SALVA os dados"""
try:
Movie.objects.create(**kwargs)
except ValidationError as e:
self.print_red(e.messages)
self.print_red('O objeto no foi salvo.\n')
def handle(self, movies, year, **options):
""" se "movies" no for nulo, transforma em inteiro """
self.verbosity = int(options.get('verbosity'))
if movies is not None:
movies = int(movies)
# busca os filmes n vezes, a partir da variavel "movies"
for i in range(movies):
# verifica as validaes
m = self.get_movie(year)
if m['imdbRating'] == "N/A":
m['imdbRating'] = 0.0
# Transforma "year" em inteiro
if "" in m['Year']:
m['Year'] = year
data = {
"title": m['Title'],
"year": m['Year'],
"released": m['Released'],
"director": m['Director'],
"actors": m['Actors'],
"poster": m['Poster'],
"imdbRating": m['imdbRating'],
"imdbID": m['imdbID'],
}
self.save(**data)
if self.verbosity > 0:
self.stdout.write('\n {0} {1} {2}'.format(i + 1, data['year'],
data['title']))
if self.verbosity > 0:
self.stdout.write('\nForam salvos %d filmes' % movies)
Uso
Usage: python manage.py initdata [options]
Faz o crawler numa api de filmes e retorna os dados.
Uso: python manage.py initdata
ou: python manage.py initdata -m 20
ou: python manage.py initdata -m 20 -y 2015
search.py
Objetivo: Localizar o filme pelo ttulo ou ano de lanamento.
from django.core.management.base import BaseCommand, CommandError
from optparse import make_option
from core.models import Movie
class Command(BaseCommand):
help = """Localiza um filme pelo ttulo ou ano de lanamento.
Uso: python manage.py search -t 'Ted 2'
ou: python manage.py search -y 2015
ou: python manage.py search -t 'a' -y 2015"""
option_list = BaseCommand.option_list + (
make_option('--title', '-t',
dest='title',
default=None,
help='Localiza um filme pelo ttulo.'),
make_option('--year', '-y',
dest='year',
default=None,
help='Localiza um filme pelo ano de lanamento.'),
)
def handle(self, title=None, year=None, **options):
""" dicionrio de filtros """
self.verbosity = int(options.get('verbosity'))
filters = {
'title__istartswith': title,
'year': year
Uso
Usage: python manage.py search [options]
Localiza um filme pelo ttulo ou ano de lanamento.
Uso: python manage.py search -t 'Ted 2'
ou: python manage.py search -y 2015
ou: python manage.py search -t 'a' -y 2015
Aqui tem um exemplo legal que eu usei como ideia pra fazer este post.
onde args so argumentos opcionais (parmetros de entrada). A funo metodo pode retornar um
valor de sada:
def metodo(args):
return args
A primeira pergunta que voc vai ter o porque do self em metodo. A resposta curta , todo
metodo criado dentro de uma classe deve definir como primeiro parametro o self. Para a resposta
longa, por favor, leia a excelente explicao que o Pedro Werneck fez:
http://www.pedrowerneck.com/o-porque-do-self-explicito-em-python-pt-br.html
A segunda pergunta : para que serve o pass?
A resposta que, em Python, ao contrario de vrias outras liguagens de programao, os blocos de
cdigo NO so definidos com os caracteres { e }, mas sim com indentao e o caractere :.
Devido a esse fato, python necessitava de algo para explicitar quando se quer definir um bloco
vazio. O pass foi criado exatamente para explicitar essa situao.
Um exemplo de uma funo vazia feita em linguagem C e a mesma funo vazia feita em Python:
void metodo(int num){
}
def metodo(num):
pass
Voltando a explicao sobre a classe: O atributo1 um atributo com valor inicial None (nada).
Poderia ser atributo1 = 0, por exemplo.
Importante: Note que para nome de classes usamos PalavrasComeandoPorMaiscula (isso
tambem conhecido como "CamelCase") e para nome de mtodos (funes) usamos
minsculas_separadas_por_underscore. Esta uma conveno adotada pelos Pythonistas segundo
o Guia de Estilo PEP 8 - Style Guide for Python Code escrito por Guido Van Rossum.
Note que definimos dois parmetros a e b (dentro do parnteses). E o self.a um novo campo.
Poderamos definir
def __init__(self, param1, param2):
self.a = param1
self.b = param2
para no confundir, mas usualmente usamos o mesmo nome tanto no parmetro quanto no novo
campo.
Como dito antes, definimos os valores iniciais apenas uma vez e depois apenas usamos os mtodos
para calcular os valores.
Podemos rodar o Python no modo modo interativo pelo terminal e importar a classe (veja este
video).
$ python3
>>>
>>>
>>>
>>>
>>>
>>>
Soma: 130
Subtrao: 126
Multiplicao: 256
Diviso: 64.0
Resultado:
>>> 54
Importante: apesar de no fazer parte do escopo deste artigo, mas vejam este video Operadores
aritmticos e diviso no Python 2 e Python 3, explicando sobre a diferena no resultado da diviso
nas duas verses do Python.
Vejam tambm este artigo sobre ponto flutuante: Floating Point Arithmetic Issues and Limitations.
Exemplo 2 - Calculadora
Agora faremos uma classe sem valor inicial e com dois parmetros para todos os mtodos.
#calculadora2.py
class Calculadora(object):
def soma(self, a, b):
return a + b
def subtrai(self, a, b):
return a - b
def multiplica(self, a, b):
return a * b
def divide(self, a, b):
return a / b
A vantagem de colocar os parmetros em cada mtodo, que podemos calcular qualquer valor sem
ter que instanciar uma nova classe para cada valor diferente.
Podemos rodar o Python no modo modo interativo pelo terminal e importar a classe (veja este
video).
$ python3
>>> from user import User
>>> u1 = User('Regis', 35)
>>> u1.save()
>>> u2 = User('Fabio',20)
>>> u2.save()
>>> print(User.all())
Agora os comentrios:
Definindo a classe
class User(object):
Define um atributo que servir como contador inicial e um atributo objects (tupla vazia) que
uma lista de instncias de User que foram salvos (que chamaram o mtodo save).
seq = 0
objects = []
Inicializando os atributos, id comea com None, pois a instncia foi criada mas ainda no foi
salva.
self.id = None
self.nome = nome
self.idade = idade
Mtodo para salvar os dados ele incrementa o atributo de classe que conta quantas instncias foram
salvas e adiciona a instncia na lista de objects.
def save(self):
self.__class__ acessa a classe que criou a instncia, assim possvel acessar o atributo de
seq. Aqui poderia ser usado User.seq, porm caso User fosse herdado, o seq seria o de User
e no da classe filha.
self.__class__.seq += 1
self.id = self.__class__.seq
Da mesma forma que acessamos seq, acessamos objects e feito um append com a instncia.
self.__class__.objects.append(self)
Retorna uma representao do objeto como str, usado em converses para string. Exemplo:
str(my_user), print my_user.
def __str__(self):
return self.nome
Retorna uma representao do objeto usada para outros objetos. Exemplo: quando convertida uma
lista de user para string.
def __repr__(self):
Class method usado para acessar todas as instncias salvas (que chamaram o mtodo save). Aqui
usamos um @classmethod, pois faz mais sentido ser um mtodo de classe do que de instncia,
pois estamos retornando informaes da classe e no de uma instncia isolada.
@classmethod
def all(cls):
return cls.objects
Aps chamar o save para as duas instncias elas so guardadas e o mtodo User.all() retorna
essa lista.
2. A Ajuda.
sqlite> .help
6. Saindo do SQLite3.
sqlite> .exit
CRUD
Abra um editor de texto e salve um arquivo com o nome inserirdados.sql.
$ gedit inserirdados.sql
Nota: No caso do INSERT INTO no precisamos numerar, basta trocar o nmero do id por
NULL, exemplo:
INSERT INTO clientes VALUES(NULL, 'Carlos', '99999999999', 'carlos@email.com',
'118888-8888', 'SP');
Cuidado: se voc no usar o WHERE e escolher um id voc pode deletar todos os registros da
tabela.
15.Voc pode exibir os dados na forma de coluna.
sqlite> .mode column
Backup
$ sqlite3 Clientes.db .dump > clientes.sql
$ cat clientes.sql
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE clientes(
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
Nome VARCHAR(100) NOT NULL,
CPF VARCHAR(11) NOT NULL,
Email VARCHAR(20) NOT NULL,
Fone VARCHAR(20),
UF VARCHAR(2) NOT NULL
);
INSERT INTO "clientes"
VALUES(1,'Regis','00000000000','rg@email.com','1100000000','SP');
INSERT INTO "clientes"
VALUES(2,'Abigail','11111111111','abigail@email.com','1112345678','RJ');
INSERT INTO "clientes"
VALUES(3,'Benedito','22222222222','benedito@email.com','1187654321','SP');
INSERT INTO "clientes"
VALUES(4,'Zacarias','33333333333','zacarias@email.com','1199999999','RJ');
COMMIT;
Relacionando tabelas
Todos devem saber que num banco de dados relacional a chave estrangeira ou FOREIGN KEY
tem um papel importante no relacionamento entre duas tabelas. Veremos aqui como relacionar duas
tabelas.
Primeiros faamos um backup do nosso bd.
$ sqlite3 Clientes.db .dump > clientes.sql
Nome
CPF
Fone
UF
----------
-----------
------------
----------
----------
Regis
Abigail
Benedito
00000000000
11111111111
22222222222
rg@email.com
abigail@emai
benedito@ema
1100000000
1112345678
1187654321
SP
RJ
SP
1
1
0
Segundo Sqlite Drop Column, no tem como "deletar" uma coluna, ento precisamos criar uma
nova tabela clientes_novo com os campos que precisamos e copiar os dados da primeira tabela para
esta.
sqlite> INSERT INTO clientes_novo (id, Nome, CPF, Email, Fone, bloqueado)
...> SELECT id, Nome, CPF, Email, Fone, bloqueado FROM clientes;
Veja que selecionamos os campos da tabela clientes e a inserimos em clientes_novo. Note que no
copiamos o campo UF porque agora ele da tabela cidades.
Agora podemos deletar a tabela "antiga".
Nome
CPF
Fone
bloqueado
----------
-----------
------------
----------
----------
Regis
Abigail
Benedito
00000000000
11111111111
22222222222
rg@email.com
abigail@emai
benedito@ema
1100000000
1112345678
1187654321
1
1
0
Agora voc ter que popular as cidades e definir a cidade_id em cada cliente. Lembrando que a
chave AUTOINCREMENT, ento use NULL.
sqlite> INSERT INTO cidades VALUES (NULL,'Campinas','SP');
sqlite> INSERT INTO cidades VALUES (NULL,'Sao Paulo','SP');
sqlite> INSERT INTO cidades VALUES (NULL,'Rio de Janeiro','RJ');
cidade
---------Campinas
Sao Paulo
Rio de Jan
uf
---------SP
SP
RJ
Resultado.
sqlite> SELECT * FROM clientes;
id
cidade_id
------------------1
2
3
Nome
CPF
Fone
bloqueado
----------
-----------
------------
----------
----------
Regis
Abigail
Benedito
00000000000
11111111111
22222222222
rg@email.com
abigail@emai
benedito@ema
1100000000
1112345678
1187654321
1
1
0
Faamos um INNER JOIN para visualizar todos os dados, inclusive a cidade e o uf.
sqlite> SELECT * FROM clientes INNER JOIN cidades ON clientes.cidade_id =
cidades.id;
id
cidade_id
Nome
cidade
CPF
Email
uf
Fone
bloqueado
3
1
2
------------
----------
----------
rg@email.com
1100000000
abigail@emai
1112345678
benedito@ema
1187654321
ListaDeReproducao
context_object_name = 'listas_de_reproducao'
def get(self, request, *args, **kwargs):
data = serializers.serialize("json", self.get_queryset())
return HttpResponse(data, content_type='application/json')
O contedo desta resposta o retorno de self.get_queryset() j serializado no formato JSON. Algo
como:
[
{
"pk":1,
"model":"app_exemplo.listadereproducao",
"fields":{
"modificado":"2010-03-13 12:12:45",
"audios":[
1,
2,
3
],
"criado":"2010-01-26 15:25:26",
"titulo":"Animiais",
"slug":"Animais",
"descricao":"Alguns efeitos sonoros de animais."
}
},
{
"pk":2,
"model":"app_exemplo.listadereproducao",
"fields":{
"modificado":"2010-05-30 08:16:53",
"audios":[
4,
5,
6,
7
],
"criado":"2010-01-05 14:12:28",
"titulo":"Clicks",
"slug":"clicks",
"descricao":"Efeitos sonoros de CLICKs."
}
},
// ...
]
Para um exemplo isto serve, mas talvez voc realmente queira personalizar isto antes de transformlo em Json. Por exemplo se voc quer serializar um queryset de usurios, dependendo de como sua
query foi composta, pode trazer o campo 'senha' e, talvez, voc queira omit-lo deste retorno.
Contudo creio que no haver grandes problemas para fazer isto, uma vez que com
self.get_queryset() voc consegue manipular bem estes resultados, antes de serializ-los.
Concluso
Bem, este foi um exemplo simples, em um outro artigo creio que farei algo como retornar o Json e
trabalhar ele com Jquery.
Extra:
Se voc quisesse, ao invs de Json, retornar um XML, bastaria modificar duas simples coisas, neste
simples exemplo, claro:
# ...
serializers.serialize("xml", self.get_queryset())
return HttpResponse(data, content_type='application/xml')
Many different methods exist for accomplishing this task, but these solutions often require
duplicating template code, dont address rendering the same view as both a standalone page and the
contents of a modal, or dont account for redirects when submitting forms.
I recently found myself trying to render a Django view as both a modal and a standalone page and
had the following requirements:
minimize code repetition
update the modal with any form errors
close the modal on successful submission
I was able to accomplish this task with a few lines of Python, a few lines of JavaScript, and a minor
template change.
Server-Side Changes
The server-side changes consisted of creating an AjaxTemplateMixin to render a different
template for AJAX requests and making a small change to an existing template.
An AjaxTemplateMixin
1 class AjaxTemplateMixin(object):
2
3
def dispatch(self, request, *args, **kwargs):
4
if not hasattr(self, 'ajax_template_name'):
5
split = self.template_name.split('.html')
6
split[-1] = '_inner'
7
split.append('.html')
8
self.ajax_template_name = ''.join(split)
9
if request.is_ajax():
10
self.template_name = self.ajax_template_name
11
return super(AjaxTemplateMixin, self).dispatch(request, *args,
**kwargs)
The first step required writing a mixin to add an ajax_template_name attribute Djangos
class-based views. If this attribute is not explicitly defined, it will default to adding _inner to the
end of the template_name attribute. For example, take the following FormView class:
1 class TestFormView(SuccessMessageMixin, AjaxTemplateMixin, FormView):
2
template_name = 'test_app/test_form.html'
3
form_class = TestForm
4
success_url = reverse_lazy('home')
5
success_message = "Way to go!"
4 {% load crispy_forms_tags %}
5 <div class="row">
6
<form class="form-horizontal" action="{% url 'test-form' %}"
method="post">
7
{% crispy form %}
8
<input type="submit" class="btn btn-submit col-md-offset-2">
9
</form>
10 </div>
11 {% endblock content %}
to:
1
2
3
4
5
{% extends 'test_app/home.html' %}
{% block content %}
{% include 'test_app/test_form_inner.html' %}
{% endblock content %}
All weve done here is moved the HTML within the content block to its own template. The example
template uses django-crispy-forms to generate the form markup using Bootstrap CSS classes but
this is not a requirement.
Front-end Changes
At this point, rendering your view is easy, unless it contains a form.
to your template. Behind the scenes, Bootstrap is using the data attributes to call jQuerys
.load() method to make an AJAX call to the test-form url and replace the HTML within
#form-modal. However, there are a couple problems with this:
Using data attributes replaces the entire contents of the modal, so your template will need to
contain the .modal-dialog, .modal-content and .modal-body DIVs to render
properly.
jQuerys .load() is only called once the first time the modal is opened.
Any redirects that occur, such as from submitting a form, will redirect the entire page.
If none of this matters to you, then great, youre done! Otherwise, keep reading.
This code binds to the click event on #comment-button and loads the /test-form/ HTML
asynchronously into the body of the modal. Since this is an AJAX call, the
test_form/test_form_inner.html template will be rendered and the form will be
displayed without any site navigation or footer.
Additionally, this code also calls formAjaxSubmit(). This function binds to the forms submit
event. By calling preventDefault(), the callback function prevents the form from performing
its default submit action. Instead, the forms content is serialized and sent via an AJAX call using
the forms defined action and method.
If the server sends back a successful response, the success function is called. The xhr parameter
contains the HTML received from the server. Note that a successful response from the server does
not mean that the form validated successfully. Therefore, xhr is checked to see if it contains any
field errors by looking for the has_error Bootstrap class in its contents. If any errors are found,
the modals body is updated with the form and its errors. Otherwise, the modal is closed.
class Signup(CreateView):
model = User
fields = ['first_name', 'last_name', 'email', 'password']
def get_form(self, form_class):
form = super(Signup, self).get_form(form_class)
form.fields['password'].widget = forms.PasswordInput()
return form
from django import forms
class SignupForm(forms.ModelForm):
class Meta:
model = User
fields = ['first_name', 'last_name', 'email', 'password']
widgets = {
'password': forms.PasswordInput()
}
class Signup(CreateView):
form_class = SignupForm
model = User
Summary
In conclusion, we were able to define our form and view in Django and render it correctly in a
Bootstrap modal by adding one short Django mixin, making a small change to an existing template,
and adding a few lines of JavaScript.