terça-feira, 13 de dezembro de 2011

Integração django-ckeditor e o South

Para todos aqueles que também utilizam o South e o django-ckeditor, um poderoso editor html já integrado com o admin do django, uma dica:

Para efetuar as migrações do south, edite o arquivo fields.py dentro do seu ENV\lib\site-packages\ckeditor e adicione as seguintes linhas no fim do arquivo:


try:
    from south.modelsinspector import add_introspection_rules
    add_introspection_rules([], ["^ckeditor\.fields\.RichTextField"])
except:
    pass

Isso permitirá que vc faça as migrações sem problemas.

hasta!




segunda-feira, 7 de novembro de 2011

Permissão somente para usuários do admin (staff_member)

As vezes, algumas views requer permissões mais rígidas, como por exemplo alguma view de integração, carga, ou até mesmo para dados sigilosos.

Para tal, basta utilizar o decorator staff_member_required, que permite apenas acesso aos membos da equipe.

Para fazer uso do mesmo basta importar em seu arquivo views.py ou admin_views.py :

from django.contrib.admin.views.decorators import staff_member_required

E na view utilizar como qualquer outro decorator:

@staff_member_required
    def sua_view(request):
    #seu código aqui


hasta!

sexta-feira, 4 de novembro de 2011

Forçar incluir pelo menos um dos inlines

Normalmente temos casos que a inclusão de um determinado conteúdo, depende de outro e para facilitar a vida do usuário (e a nossa), o django possui um recurso muito interessante: O Admin Inline.

Este é util para quando, por exemplo, iremos inserir um conteúdo com múltiplas fotos, sendo que cada foto possui uma legenda.

Para tal, não precisamos disponibilizar o admin de Fotos, visto que não tem sentido nenhum o usuario inserir uma foto, fora de algum conteúdo.

Até aqui tudo tranquilo e o inline fica assim:


from django import forms
from models import Foto, Conteudo


class FotoInline(admin.TabularInline):
model = Foto
extra = 0

class ConteudoAdmin(admin.ModelAdmin):
       inlines = [
               FotoInline
      ]



Desta forma o django cria os inlines dentro do conteudo para inserir quantas fotos quiser.

E se, nosso layout obrigasse o conteúdo a ter pelo menos uma foto? Não precisa socar o designer a seu lado não, nem muito menos colocar campos obrigatórios de  foto e legenda no model de Conteúdo, basta utilizar um formset:


class Verifica_FK_Formset(forms.models.BaseInlineFormSet):
def is_valid(self):
return super(Verifica_FK_Formset, self).is_valid() # and not any([bool(e) for e in self.errors])

def clean(self):
count = 0
for form in self.forms:
try:
if form.cleaned_data and not form.cleaned_data.get('DELETE', False):
count += 1
except AttributeError:
pass
if count < 1:
raise forms.ValidationError('Inclua pelo menos uma linha de %s' % (self.model._meta.verbose_name,))


E alterar o seu inline para que fique da seguinte forma:


class FotoInline(admin.TabularInline):
formset = Verifica_FK_Formset
model = Foto
extra = 0

Desta forma, ao menos um item do inline de Fotos deverá ser inserido quando for inserir e/ou alterar um Conteúdo.

hasta!


terça-feira, 25 de outubro de 2011

Caught NoReverseMatch while rendering..

Algumas aplicações que utilizam do fantástico recurso de urls nomeadas, precisam ter os includes declarados no urls.py raiz do projeto.

Nem sempre a gente lembra, e acaba pegando umas telas bonitas dessa:



Basta uma conferida no arquivo urls.py da raiz e corrigir o problema incluindo as urls que faltam.


hasta!

segunda-feira, 17 de outubro de 2011

Plugins Úteis - Sorl e o (muito util) ThumbnailField

Para quem utiliza a fantástica biblioteca Sorl Thumbnail (http://pypi.python.org/pypi/sorl-thumbnail), tem uma funcionalidade muito útil além da inclusion tag {% thumbnail %}

Com a inclusion tag, é possível redimensionar e/ou cortar, uma imagem de acordo com a necessidade. Para isso, basta utilizar assim no seu template:

{% load thumbnail %}

A linha acima deve ser colocar no começo do arquivo para carregar as tags da sorl para seu template. E para a imagem fazemos:

<img src='{% thumbnail seu_objeto.campo_foto 150x150 crop,upscale %}' />

Aqui temos um exemplo em que será gerada uma imagem de 150px de largura por 150px de altura. As opções crop,upscale são opcionais e servem para corte e redimensionamento, respecticamente.

Há uma certa desvantagem em utilizar desta forma. A thumb somente será gerada quando alguma requisição for feita para a página, e após isso o arquivo físico da thumb é gerado em tempo de execução. Posteriormente, se a thumb não for trocada, o sistema utiliza a thumb gerada na primeira requisição ao invés de gerar uma nova.

Uma outra opção, e fazer a geração de todas as thumbs utilizadas para uma mesma foto, no momento que a foto é inserida ou alterada. Para isso temos o ThumbnailField.

No seu model, já com a sorl instalada no seu projeto e/ou no virtualenv, faça:

No ínicio do arquivo models.py que for utilizar thumbs, import o ThumbnailField:

from sorl.thumbnail.fields import ThumbnailField

E na sua classe, crie o campo com o campo importado da seguinte forma:

class SuaClasse(models.Model):
    foto = ThumbnailField(
upload_to="uploads/banners/home/%Y",
help_text=u"Tamanho mínimo e proporcional a 1024x768",
options = ('upscale',),
size = (1920,1000),
generate_on_save = True,
extra_thumbnails={
'1024x768':{ 'size':(1024,768), 'options':('upscale',) },
'1280x1024':{ 'size':(1280,1024), 'options':('upscale',) },
'1280x800':{ 'size':(1280,800), 'options':('upscale',) },
'1440x900':{ 'size':(1440,900), 'options':('upscale',) },
'1366x768':{ 'size':(1366,768), 'options':('upscale',) },
},

Deste modo, teremos 6 arquivos para cada imagem que for inserida.

  • A original foto,  que terá no máximo 1920x1000 px de tamanho, sendo que fará uso do upscale
  • E 5 extra_thumbnails, onde cada uma terá um tamanho próprio, também utilizando o upscale.

No template para utilizar o campo foto,  nada muda, continua sendo :

{{ seu_obj.foto }}

Já para acessar alguma das thumbs, utilize:

{{ seu_obj.foto.extra_thumbnails.NOME_DO_THUMBNAIL }} ,  por exemplo:

{{ seu_obj.foto.extra_thumbnails.1280x1024 }} 


Em alguns casos temos que acessá-los em uma view, seja para montar um json para o ajax, ou até mesmo um xml pro inútil e arcaico Flash. Para isso utilize:

seu_obj.foto.extra_thumbnails_tag['1280x800']


Outra opção é criar um model, muito útil para quando deseja-se mostrar a thumb no change list do admin. Para isso, utilize:


def thumb_admin(self):
from sorl.thumbnail import get_thumbnail
im = get_thumbnail(self.imagem, '120x120', crop='center', quality=99)
if im:
return  '<a href="%s/"><img src="%s" alt="Imagem" /></a>' % (self.id, str(im.url))
return  'Sem foto'
thumb_admin.is_safe = True
thumb_admin.allow_tags = True
thumb_admin.short_description = 'Thumb'


hasta!








terça-feira, 11 de outubro de 2011

Forçando download de arquivos no Django

Muitas vezes, nossas classes possuem módulos que tem imagens em alta definição, ou até mesmo arquivos referente ao contexto da classe, tais como manuais em pdf, ou em outro formato qualquer.

Para algumas situações é melhor que o visitante faça download do arquivo, mesmo que o browser possua os plugins necessários para exibí-lo. Para forçar o download basta utilizar a view abaixo:


def download_view(request):
 from django.http import HttpResponse, Http404
 from os import path
 import mimetypes

 arquivo = "%s/%s" % (settings.MEDIA_ROOT, request.GET.get('filename'), ) 

 if not (path.exists(arquivo)):
  raise Http404()

 mimetype, encoding = mimetypes.guess_type(arquivo)

 if mimetype is None:
  mimetype = 'application/force-download'

 file = arquivo.split("/")[-1]

 response = HttpResponse(open(arquivo, 'r').read())
 response['Content-Type'] = mimetype
 response['Pragma'] = 'public'
 response['Expires'] = '0'
 response['Cache-Control'] = 'must-revalidate, post-check=0, pre-check=0'
 response['Content-Disposition'] = 'attachment; filename=%s' % file
 response['Content-Transfer-Encoding'] = 'binary'
 response['Content-Length'] = str(path.getsize(arquivo))
 return response


O parâmetro filename vem por get, permitindo que a mesma view seja utilizada para vários downloads de diferentes classes. O que pode ser ajustado é o caminho da definição da variável filename de acordo com a necessidade.

hasta!

terça-feira, 27 de setembro de 2011

Como ordenar uma listagem de produtos pelos mais recentes, deixando os esgotados pro fim?

Recentemente tive que fazer a ordenação descrita no título deste post.

A solução encontrada foi a utilização da poderosa ferramenta extra que o django oferece em seu ORM.

Tinha a seguinte situação:

models.py

class Produto(models.Model):
     ...
     ...
     estoque = models.IntegerField()
     ...
     ...


Meu campo estoque gerencia a quantidade disponível de cada produto na loja. 

Fiz da seguinte forma no meu arquivo view.py:

def lista_produto(request):
     ...
     ...
     produtos = Produto.objecst.all().extra(select={'esgotado': "( if (produtos_produto.estoque > 0,0,-10000) )+produtos_produto.id"}).extra( order_by = ['-esgotado'] )
     ...
     ...

Juntamente com todos os campos da classe Produto, crio um campo a mais para o retorno, sendo este chamado de esgotado. Para este campo será executado a query passada a seguir para o banco de dados:

 if (produtos_produto.estoque > 0,0,-10000) )+produtos_produto.id

Caso o estoque for maior que 0, o IF irá retornar 0, caso contrário será retornado -10000. O valor negativo aqui é arbitrário, podendo este ser qualquer valor, desde que seu módulo seja pelo menos igual ao maior id do banco.



Ao valor do IF é adiconado o ID do produto corrente.

Desta forma todos os produtos que não tiverem estoque, será trazido neste campo um valor negativo visto que a conta ficará -10000 + ID,  e os que possuírem algum estoque, será 0 + ID.

Finalmente, passamos a nova ordenção, esgotado DESC, também pelo extra:
.extra( order_by = ['-esgotado'] )

Assim, todos os produtos com estoque ficarão com um valor positivo para o valor esgotado, e os que não tiverem, será um valor negativo, ficando por últimos com a ordenação decrescente.

hasta!


segunda-feira, 26 de setembro de 2011

Enviando emails no Django através de um pool de contas autenticadas

Recentemente passei por um problema com relação ao envio de emails. O cliente possuia as constas hospedadas em um servidor de emails que limitava o envio diário. Logo, com todos os contatos, logs de erros, logs de controle, etc sendo enviados por uma mesma conta, tinha dias que excedia tal limite.

Para que isso não voltasse a ocorrer, a idéia era ter uma lista de possíveis conexões, para que em caso de falha de autenticação ou limite, utilizasse a outra. Logo veio o problema. No settings.py apenas há espaço para uma autenticação de email.

Então foi que fiz o seguinte:

send_email_by_pool.py ( na raiz do projeto )


import random
import smtplib
from django.conf import settings
from django.core.mail import send_mail, get_connection

def send_mail_by_pool(subject, message, from_email=None, recipient_list=None, fail_silently=False,
auth_user=None, auth_password=None, connection=None):
"""
Seleciona a conexao atual usando um pool de conexoes
"""
global _valid_connections

ret = 0
while _valid_connections and ret == 0:
try:
connection = connection or choose_connection()
from_email = from_email or connection.username

auth_user = auth_user or connection.username
auth_password = auth_password or connection.password

ret = send_mail(subject, message, from_email, recipient_list, fail_silently, auth_user, auth_password, connection)

except (smtplib.SMTPAuthenticationError, smtplib.SMTPSenderRefused):
if not connection:
raise

_valid_connections.remove(connection._pool_name)

return ret

_valid_connections = settings.EMAIL_CONNECTIONS.keys()
def choose_connection():
global _valid_connections
chosen = random.choice(_valid_connections)
conn_settings = settings.EMAIL_CONNECTIONS[chosen]
connection = get_connection(**conn_settings)
connection._pool_name = chosen
return connection

no settings.py:



EMAIL_CONNECTIONS = {
'default': {
'backend': 'django.core.mail.backends.smtp.EmailBackend',
'host': 'smtp.seu_servidor.com.br',
'username': 'seu_email@ seu_servidor.com.br',
'password': 'sua_senha',
'use_tls': False, # para o caso de usar TLS, colocar True
'fail_silently': False,
},
'second': {
'backend': 'django.core.mail.backends.smtp.EmailBackend',
'host': 'smtp.seu_servidor.com.br',
'username': 'seu_email2@ seu_servidor.com.br',
'password': 'sua_senha2',
'use_tls': False, # para o caso de usar TLS, colocar True
'fail_silently': False,
},
}

E na sua view:


from send_email_by_pool import *

subject = "Testando envio"
message = "oi"
from_email = None
recipient_list = ['zejuniortdr@gmail.com',]
fail_silently = False
auth_user = None
auth_password = None 
connection = None

ret = send_mail_by_pool(subject, message, from_email, recipient_list, fail_silently, auth_user, auth_password, connection)



Desta forma, o envio ocorrerá passando por tantas contas quantas forem necessárias até enviar, desde que haja uma conta autorizada e que não tenha excedido o limite.

hasta!



sexta-feira, 23 de setembro de 2011

Upload em Python

Em alguns caso é necessário fazer um upload manual no python.

Para tal, fiz o seguinte:



def upload(request):
target = os.path.join(settings.MEDIA_ROOT, 'uploads/anuncios/logo/2010')
if request.method == 'POST':
if request.FILES.get('logo_file'):
f = request.FILES['logo_file']
try:
destination = open('%s/%s' % (target, f.name), 'wb+')
for chunk in f.chunks():
destination.write(chunk)
destination.close()
except:
retorno = "{error:'100', msg:'Problema: Erro de permissão para escrever em arquivo'}"
return HttpResponse(retorno)

retorno = "{error:'', msg:'Sucesso', arquivo:'%s'}" % (f.name)
return HttpResponse(retorno)
else:
retorno = "{error:'200', msg:'Problema: Sem FILES'}"
return HttpResponse(retorno)
else:
retorno = "{error:'300', msg:'Problema: Sem Post'}"
return HttpResponse(retorno)

Plugins Úteis - South - Uma app para Django muito útil para gerenciamento do Banco de Dados


South

South é uma aplicação do django responsável por gerenciar as modificações feitas no projeto que influenciam em criação/edição/remoção de tabelas e/ou campos no banco de dados.

Para instalar o south no ambiente:
pip install south
adicionar ele na installed_apps

Com o South NÃO DEVE-SE USAR o syncdb do django para criação das tabelas de suas apps. Apenas deve ser rodado o syncdb para criação das tabelas referente as aplicações padrões do settings e mais a do south. 

Para criação das tabelas de uma nova aplicação utilizar:
python manage.py schemamigration NOME_DA_APP --initial

Para criação de todas as tabelas do projeto, basta omitir o nome da app.

Os comandos acima vão criar apenas os schemas de migração, nada será alterado no banco de dados. Para aplicar as migrações deve-se utilizar o comando:
python manage.py migrate NOME_DA_APP

Para todos os esquemas, basta omitir o nome da app.

Depois da situação inicial criada, caso haja necessidade de adicionar/remover campos nos models, utilizar seguinte comando para sincronizar os schemas:
python manage.py schemamigration NOME_DA_APP --auto

E para aplicar as migrações da mesma forma descrita anteriormente:
python manage.py migrate NOME_DA_APP

Caso deseje aplicar o South em algum projeto que não tenha, e as tabelas já tenham sido criadas, basta instalar o South como descrito acima, e utilizar o comando:
python manage.py convert_to_south NOME_DA_APP 


O south cria no banco de dados algumas tabelas para controle do que já foi migrado para não tentar fazer novamente, caso deseje informar o south que aquela migração já tenha sido realizada, possivelmente para corrigir algum problema, basta utilizar o comando:
python manage.py migrate --fake

Desta forma ele vai apagar as migrações contidas nos schemas gerados e colocar no banco como realizada, sem fazer nenhuma alteração no banco.

quinta-feira, 22 de setembro de 2011

Permissão somente para usuários do admin (staff_member)

As vezes, algumas views requer permissões mais rígidas, como por exemplo alguma view de integração, carga, ou até mesmo para dados sigilosos.

Para tal, basta utilizar o decorator staff_member_required, que permite apenas acesso aos membos da equipe.

Para fazer uso do mesmo basta importar em seu arquivo views.py ou admin_views.py :

from django.contrib.admin.views.decorators import staff_member_required

E na view utilizar como qualquer outro decorator:

@staff_member_required
def sua_view(request):
        #seu código aqui

sexta-feira, 16 de setembro de 2011

Correndo uma lista de valores similar a lista de impressão

Para uma entrada  1;2;3-6;7;8-10, por exemplo, assim como na impressão seria impresso as páginas 1, 2, de 3 a 6, 7 e de 8 a 10, precisei fazer um esquema para liberação de pedidos segundo essa entrada para liberar faixas distintas de pedidos.

Para tal, uso a def abaixo:

def corre_cadeia(lista_char, separador_item, identificador_lista):
 lista  = lista_char.split(separador_item)
 nova_lista = []
 for l in lista:
  if l.find(identificador_lista) == -1:
   nova_lista.append(int(l))
  else:
   inicio, termino = l.split(identificador_lista)
   inicio = int(inicio)
   termino = int(termino)
   i = inicio
   while i<= termino:
    nova_lista.append(i)
    i+=1
 return nova_lista

Ex:
>>> lista = '1;2;3-6;7;8-10'
>>> corre_cadeia ( lista, ';' , '-')
[1,2,3,4,5,6,7,8,9,10]

hasta!

segunda-feira, 8 de agosto de 2011

Script para geração de senhas com módulos nativos do python

Gerar senhas com um alto nível de segurança nunca foi tão fácil. Para tal, basta utilizar o código abaixo:

import string
from random import choice
size = 16
''.join([choice(string.letters + string.digits) for i in range(size)])


hasta!

quinta-feira, 21 de julho de 2011

Instalando a PIL no Ubuntu 11.04 com python 2.7

  1. Instalar bibliotecas via APT:
    $ sudo apt-get install libjpeg-dev libpng-dev zlib1g-dev liblcms1-dev python-dev
  2. baixar o decoder jpeg aqui. Instalá-lo:
    $ cd jpeg-8c
    $ ./configure --enable-shared
    $ make
    $ make install
  3. baixar PIL. Editar setup.py:
    1
    2
    3
    
    $ tar -xvf PIL-1.2a0-20110108.tar.gz
    $ cd PIL-1.2a0
    $ nano setup.py
    Olhe para a declaração de JPEG_ROOT e ZLIB_ROOT e substituí-los da seguinte forma:
    JPEG_ROOT = “/usr/local/include”
    ZLIB_ROOT = “/usr/local/include”
  4. Instale
    1
    2
    3
    
    $ python setup.py build_ext -i
    $ python selftest.py
    $ sudo python setup.py install
  5. Abra o shell do python e se as coisas correram bem, o seguinte código trará nenhum erro:
    1
    2
    
    $ import PIL
    $ import _imaging

Se mesmo assim não funcionar, pelo gerenciador de pacotes (Synaptic) também é possivel fazer a instalação.

Formatando moeda segundo padrão do sistema operacional

Várias vezes precisamos formatar moedas e sempre é uma briga. Para facilitar um pouco a vida utilizo esta def abaixo, que pega o locale do sistema operacional e já retorna o valor informado formatado:


def moeda(valor):
if valor != None:
import locale
locale.setlocale( locale.LC_ALL, '' )
return locale.currency( valor, grouping=True )
return ''


Ela pode ser usada como filtro ou como algum método com apenas pequenos ajustes.

hasta!

quinta-feira, 28 de abril de 2011

Migrando para versão 1.3 - parte 3 - o CSRF

O CSRF é uma melhoria que vem desde da versão 1.2.X, impedindo que POSTs externos enviem informações para seu site. Ele protege os forms através de uma chave critptografada que é validada no envio do form.

Para migrar seus forms ( contato / cadastro / login / etc) para suportar o CSRF é necessário alguns passos:


  1. Certifique-se que os middlewares do crsf estejam no settings, confome a parte 1 deste tutorial (http://djangoweb.blogspot.com/2011/04/migrando-para-versao-13-parte-1-o.html)

  2. Coloque no seu form, a tag para geração do token do CSRF:
    {% csrf_token %}

  3. Na view que receberá o POST, valide o token enviado pelo form da seguinte forma:
    from django.core.context_processors import csrf
    c = {}
    c.update(csrf(request))


  4. Caso precise excluir uma view dessa validação, como quando recebe-se o post de terceiros, por exemplo, basta utilizar o decorator @csrf_exempt:

    from django.views.decorators.csrf import csrf_exempt
    @csrf_exempt
    def sua_view_aqui(request):

         
    pass


Nota: para requisições ajax, o token também deverá ser passado.

hasta!

Migrando para versão 1.3 - parte 2 - O urls.py

No arquivo urls.py a mudança é sutil.
Apenas vertifique-se de colocar a linha abaixo antes das urls:

from django.conf.urls.defaults import patterns, include, url


Para importar outros arquivos urls.py ( de aplicações por exemplo ), a sintaxe é assim:

(r'^sua-url/', include('sua-app.urls')),

Migrando para versão 1.3 - parte 1 - O settings.py

Para adequar os projetos desenvolvidos em versões anteriores para a 1.3, foi preciso alguns ajustes no settings

A setting DATABASE agora é um dicionário com as informações de conexão do banco. Deixe-a da seguinte forma:

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'pub6l_db',
'USER': 'pub6l_usr',
'PASSWORD': '3f8ezxegmx',
'HOST': '',
'PORT': '',
}
}


Adicione as settings para os arquivos estáticos :

STATIC_ROOT = ''
STATIC_URL = '/static/'
ADMIN_MEDIA_PREFIX = '/static/admin/'
STATICFILES_DIRS = (
# Put strings here, like "/home/html/static" or "C:/www/django/static".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
)
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
)


Na setting MIDDLEWARE_CLASSES, certifique-se que tenha todas as linhas abaixo:

'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',


Verifique também se a setting INSTALLED_APPS contém todas as linhas abaixo (além das suas aplicações claro):  

'django.contrib.auth', 
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.admin',

hasta!



quarta-feira, 27 de abril de 2011

WSGIRequest object has no attribute page

Problema identificado pela falta do middleware do django-pagination.

Coloque a linha abaixo na setting MIDDLEWARE_CLASSES:
'pagination.middleware.PaginationMiddleware',


hasta!

terça-feira, 19 de abril de 2011

Matando a sessão de um usuário remotamente

Hoje presenciei uma nova necessidade. Precisava deslogar um usuário/cliente a partir da administração. Como de costume, no Django não é muito complicado. Tenho uma aplicação de acesso que recebe uma entrada contendo qual é o cliente, hora de acesso e a chave da session gerada para ele.
Gravo na coluna sessão a session_key no ato do login,  que pode ser obtida assim:

request.session.session_key

E para deslogar o usuário, basta fazer isso em alguma view:


from django.contrib.sessions.backends.db import SessionStore
s = SessionStore(session_key=skey)
s.delete()


hasta!



quarta-feira, 12 de janeiro de 2011

Como converter html special chars

Caso seja necessário converter um espaço " " para &nbsp; "<" para &lt; ">" para &gt; e assim por diante, basta fazer o seguinte:

from django.utils.html import escape
print escape('<div class="teste">teste de conversão de caracteres especiais do html</div>')


hasta!

terça-feira, 11 de janeiro de 2011

Efetuando buscas utilizando "OR"

Para realizar buscas utilizando  "OR" basta fazer conforme abaixo:

from django.db.models import Q
resultados = <Classe>.objects.filter(Q(<campo1>__icontains=<keyword>) | Q(<campo2>__icontains=<keyword>))

Note que o icontans apenas foi utilzado como exemplo, poderia ser feito com quaisquer outros fields lookups (http://docs.djangoproject.com/en/dev/ref/models/querysets/#field-lookups)

Substituindo os devidos campos por seus respectivos nomes, será obtido em resultados uma query que busca em um ou em outro campo satisfazendo a respectiva condição.

hasta!

Paginando Resultados com Django Pagination

Nada de limit, top. Não iremos usar nem o slice na view e não será necessário nem criar controles para pegar a página atual, a anterior controlar parametros já enviados de busca.

Como? Django Pagination.

Basta pegar o projeto disponibilizado aqui (http://code.google.com/p/django-pagination/)  colocá-lo na raiz do seu projeto.

No arquivo settings.py poucas alterações:

  • Adicione o Pagination a tupla INSTALLED_APPS:
    • ...
      'pagination',
      ...
  • Adicione o Middleware do Pagination à tupla MIDDLEWARE_CLASSES:
    • ...
      'pagination.middleware.PaginationMiddleware',
      ...
  • E por sim no template, onde quiser paginar os resultados basta seguir a seguintes alterações:
    • Carregue o template_tags do Pagination:
      • {% load pagination_tags %}
    • Defina logo acima do "for" que correrá todos os resultados obtidos na view a seguinte linha, substituindo com as devidas informações:
      • {% autopaginate <SUA_QUERY_SET> <NRO_REGISTROS_POR_PAG> %}
    • Para os botões de contre, adicone o código a seguir:
      • {% paginate %}
Lembre-se de não filtrar os resultados na sua view, pra que o trabalho se tem algo eficiente que faz por você? 

hasta!

terça-feira, 4 de janeiro de 2011

Erro: ManagementForm data is missing or has been tampered with

Quando a versão dos templates em TEMPLATE_DIRS/admin está incompatível com a versão do django que está rodando, normalmente faltam os campos hiddens necessários para o correto funcionamento do admin.

Caso o admin esteja personalizado ou a edição estiver no front, basta colocar a linha abaixo no template para inserir os campos necessários.

{{ formset.management_form }}


hasta!