terça-feira, 16 de dezembro de 2014

Erros para instalar dependências do virtualenv no Mac OSX Lion

Tentando instalar as dependências do ambiente virutal para trabalhar com Django no OSX Lion me deparei com os seguinte erros:

error command 'llvm-gcc-4.2' failed with exit status 1
mysql_config not found

Além do claro, clássico trabalho para instalar a PIL com suporte a JPEG.

Resolvi as coisas com o a mesma solução: BREW (http://brew.sh/)

Depois de instalar o brew, desinstale PIL e Pillow, caso estejam instaladas  execute os comandos:

brew install libjpeg
brew install mysql
pip install PIL
pip install Pillow


hasta!

segunda-feira, 15 de dezembro de 2014

Apps não aparecem no administrativo mesmo como superuser autenticado

Criou os apps e tem certeza que as classes no admin.py estão corretas?

Caso tenha, e/ou esteja fazendo um downgrade do django 1.7 pro 1.6, e estava funcionando antes, certifique-se que colocou a linha abaixo no urls.py antes do urlpatterns:


...
admin.autodiscover()
...


hasta!

sábado, 22 de novembro de 2014

Definindo uma linguagem inicial para o projeto, não importando a linguagem setada pelo navegador

Eis o middleware que faz a mágica:


class ForceDefaultLanguageMiddleware(object):
    """
    Ignorar cabeçalhos HTTP Accept-Language

    Isso vai forçar as máquinas I18N para escolher sempre settings.LANGUAGE_CODE
    como o idioma inicial padrão, a menos que um outro é definido através de sessões ou cookies

    Deve ser instalado * antes * qualquer middleware que verifica request.META [' HTTP_ACCEPT_LANGUAGE '] ,
    como por exemplo:  django.middleware.locale.LocaleMiddleware
    """

    def process_request(self, request):
        if request.META.has_key('HTTP_ACCEPT_LANGUAGE'):
            del request.META['HTTP_ACCEPT_LANGUAGE']


e no settings.py, basta colocar o middleware antes do LocaleMiddleware como dito acima:

MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'settings.middleware.ForceDefaultLanguageMiddleware',
    'django.middleware.locale.LocaleMiddleware',
)


hasta!

sexta-feira, 21 de novembro de 2014

Plugins Úteis - Color picker no Django Admin

Que tal um color picker parao admin quando precisar selecionar uma cor e ter certeza que o usuário não faz ideia do que #0000FF quer dizer?

Simples.

Você vai precisar de um plugin:
pip install django-paintstore


models.py

No seu models.py deixe como a seguir:

# coding: utf-8
from django.db import models
from paintstore.fields import ColorPickerField

# Create your models here.
class SUA_CLASSE(models.Model):
 """(SUA_CLASSE description)"""
 ...
 cor = ColorPickerField(help_text="Clique no campo para abrir o colorpicker.", max_length=7)
 ...

admin.py

E deixe o admin.py deixa como abaixo:

# coding: utf-8
from django.contrib import admin
from django import forms

from .models import *
# Register your models here.

class SUA_CLASSEForm(forms.ModelForm):

 class Media:
  css = {'all': ('/static/paintstore/css/colorpicker.css','/static/site/js/plugins/paintstore/init.css')}
  js = (
   '/static/paintstore/jquery_1.7.2.js',
   '/static/paintstore/colorpicker.js',
   '/static/site/js/plugins/paintstore/init.js',
  )
 class Meta:
  model = SUA_CLASSE
  fields = '__all__'

class SUA_CLASSEFormAdmin(admin.ModelAdmin):
 form = SUA_CLASSEForm
 
admin.site.register(SUA_CLASSE, SUA_CLASSEAdmin)


RESOURCES:


Os arquivos referenciados acima estão abaixo, salve-os e altere os caminhos no Form, conforme necessidade:

init.js

jQuery(document).ready(function($) {
 $('#id_cor').ColorPicker({
  onSubmit: function(hsb, hex, rgb, el, parent) {
   $(el).val('#' + hex);
   $(el).ColorPickerHide();
   $(el).css({
    color: ''+$('#id_cor_titulo').val(),
    backgroundColor: '#'+hex
   });
  },
  onBeforeShow: function () {
   $(this).ColorPickerSetColor(this.value);
  }
 }).bind('keyup', function(){
  $(this).ColorPickerSetColor(this.value.replace('#', ''));
 });

 $('#id_cor,').css({
  color: ''+$('#id_cor_titulo').val(),
  backgroundColor: $('#id_cor_titulo').val()
 });
});

init.css

#id_cor{
 width:50px;
 background-color:red;
 cursor:pointer;
 color:black;
 border:solid 1px black;
}

terça-feira, 23 de setembro de 2014

Como exibir o conteúdo html de um atributo que usa CKEDITOR dentro do readonly fields no admin

Muito específico esta necessidade? Também achava. Até precisar dela.

Imagine que tenha um form no front onde o usuário irá postar conteúdos html. No admin, conteúdos de usuários serão moderados, contudo não poderão ser editados. Nesse ponto o readonly fields ajuda muito. Mas como exibir o conteúdo html (safe) ao invés das tags?

Simples.

No seu admin.py faça da seguinte forma:


from django.contrib import admin
from .models import *


class ConteudoAdmin(admin.ModelAdmin):
 search_fields = ('nome', 'email','titulo','texto')
 list_display = ('nome', 'email','titulo','arquivo', 'data', 'hora')
 list_filter = ['data',]
 date_hierarchy = 'data'
 readonly_fields = ['nome', 'email','titulo', 'texto_html','arquivo']
 exclude = ['texto',]
 save_on_top = True

 def texto_html(self, obj):
  return u'{0}'.format(obj.texto)
 texto_html.allow_tags = True
 texto_html.short_description = 'Texto'


admin.site.register(Conteudo, ConteudoAdmin)


Note que criei um método para retornar o atributo texto do meu objeto, e permiti ao método que retornasse tags html com o allow_tags = True. Para não ficar repetido, exclui o atributo original do admin com o exclude.

hasta!

quarta-feira, 3 de setembro de 2014

Django 1.7 - Getting Started!

Saiu a versão tão esperada do Django, a 1.7.

Algumas novidades importantes antes de começarmos:

  • Suporte ao python 3.3.
  • Retirou o suporte ao python 2.6.
  • Sistema de migração de banco nativo ( integração com South ).

Vou tentar registrar aqui o que tive que fazer para iniciar um projeto e conforme for surgindo as novidades vou atualizando o post.


Como instalar uma nova versão do Python:



Bom pra começar, eu tinha o python 2.6 e por isso precisei atualizar. 

O ambiente que utilizo é windows 7 e uso uma máquina virtual com o Vagrant para rodar os projetos. Para futuras referencias abaixo, tudo será feito dentro do terminal do vagrant. Para mais informações: 

Para este início, vou instalar a versão 2.7.8 do python. Para isso faça o download em algum lugar do source e instale com os comandos abaixo:
wget https://www.python.org/ftp/python/2.7.8/Python-2.7.8.tgz
tar -xvf Python-2.7.8.tgz
cd Python-2.7.8/
./configure
make
sudo make install

Caso não tenha o make instalado, era o meu caso, utilize o comando abaixo e posteriormente a instalação conclua os passos acima.
sudo apt-get install make


Como criar o virtualenv com o python recém instalado:



Para criar o ENVo comando é o mesmo visto nos links acima:
virtualenv --no-site-packages --unzip-setuptools django17 --python=/usr/local/bin/python2.7

Aqui tive outro problema: A versão do virtualenv que tinha, não era compativel com o python 2.7. Portanto tive que atualizar  o virtualenv também:
sudo pip install virtualenv --upgrade

Depois de instalado, o comando ficou:
virtualenv-2.6 --no-site-packages --unzip-setuptools django17 --python=/usr/local/bin/python2.7

No comando acima vale prestar atenção na versão do virtualenv chamado e no parâmetro python passado ao sistema indicar o caminho do python desejado.

Com o ENV chamado django17 criado, vamos agora instalar as dependências que nosso projeto precisa, primeiramente ligue o env:
. django17/bin/activate

E instale o que desejar usando o pip, como por exemplo:
pip install django
pip install MySQL-python
pip install sorl-thumbnail==11.12.1b

A versão da sorl.thumbnail foi especificada pois a final ainda não tem compatibilidade com o Django 1.7, por isso instalei a beta.




Ajustando o settings para rodar o projeto



Achei que o settings.py nativo veio bem mais enxuto, e por hora mudarei apenas duas configurações:
LANGUAGE_CODE = 'pt-br'
TIME_ZONE = 'America/Sao_Paulo'

E no fim do arquivo adicionarei a importação das configurações que farei a sobreposição para rodar o projeto local:
try:
 from local_settings import *
except:
 pass


Criei um arquivo chamado local_settings.py no mesmo diretório do settings.py com as seguintes configurações:
# coding: utf-8
SITE_URL = 'http://localhost:8000'
DATABASES = {
 'default': {
  'ENGINE': 'django.db.backends.mysql', 
  'NAME': 'django17',        
  'USER': 'root',    
  'PASSWORD': '',    
  'HOST': '',    
  'PORT': '',    
 }
}

DEBUG = True
LOCAL = True
USE_TZ = False

if not DEBUG:
 ALLOWED_HOSTS = ['localhost',]

Ajuste neste arquivo as configurações necessárias, como DEBUG, acesso ao banco, etc.

Não se esqueça de criar uma database com o nome especificado a seu gosto no SGBD de sua preferência.


Criação das tabelas:



Para criação das tabelas padrões do django, utilize o comando abaixo. Ele será usado sempre que for instalar uma aplicação, tendo esta migrações ou não.
./manage.py migrate




Criar o super usuário do Admin:



Agora nesta versão,  o migrate (antigo syncdb) não cria mais um super usuário para o administrativo. Você deve fazer isso manualmente com o comando:
./manage.py createsuperuser

E preencha conm seu usuário, email e senha, da mesma forma que era feito antes.


Como realizar migrações dos models com makemigrations / migrate



Pra quem já utilizava o South , não terá muita dificuldade em mudar para o sistema de migração nativo que a versão 1.7 ofecere.

Para uma nova aplicação ou qualquer mudança feita no models de uma aplicação o procedimento é o mesmo:
./manage.py makemigrations debug


E depois rode novamente o migrate, passando ou não sua app:
./manage.py migrate debug




Para rodar o projeto:



Para rodar o projeto execute o comando abaixo. Ele rodará servidor e porta padrão do ambiente desenvolvimento: localhost:8000. Para mudar o servidor e/ou porta basta especificar o desejado a frente do parâmetro.
./manage.py runserver




Novidades do admin:



  • Agora é possivel alterar algumas configurações do admin sem ter que sobrepor templates. Em qualquer arquivo admin.py dentro da sua aplicação utilize o código abaixo:
# coding: utf-8

from django.contrib import admin

admin.site.site_header = u"Administração do Site"
admin.site.index_title = u"Administração do Site"
admin.site.site_title = u"Site de Administração do Django"



  • Agora os botões com cantos arredondados utilizam a propriedade border-radius do CSS ao invés de GIFs.
  • No changelist, agora as células tem uma classe CSS chamada field-<field_name> para facilitar customizações.
  • Além da sintaxe admin.site.register existente , você pode usar o decorador novo register() para registrar um ModelAdmin.
  • Agora é possível  especificar ModelAdmin.list_display_links = None desativar links na grade página de listagem.

Chamar métodos customizados do Queryset pelo Manager


class FoodQuerySet(models.QuerySet):
    def pizzas(self):
        return self.filter(kind='pizza')

    def vegetarian(self):
        return self.filter(vegetarian=True)

class Food(models.Model):
    kind = models.CharField(max_length=50)
    vegetarian = models.BooleanField(default=False)
    objects = FoodQuerySet.as_manager()

Food.objects.pizzas().vegetarian()


Veja estas e outras dicas interessantes sobre tudo que mudou para esta versão no link oficial:
https://docs.djangoproject.com/en/1.7/releases/1.7/

hasta!

quinta-feira, 14 de agosto de 2014

Gerando um PDF em Django sem template e forçando seu donwload

Você vai precisar dos seguintes aplicativos instalados no ENV:
  • reportlab==2.7

Faça uma view conforme abaixo:

#############################################################
# PDF
#############################################################
class PDFView(View):

 def post(self, request, *args, **kwargs):
  # IMPORTS NECESSARIOS
  from reportlab.pdfgen import canvas
  from reportlab.lib.pagesizes import letter, landscape, A4
  from reportlab.lib.units import inch, cm
  from reportlab.lib.colors import HexColor
  from django.conf import settings
  import os

  # VALIDAÇÃO DO CSRF_TOKEN
  c = {}
  c.update(csrf(request))
  
  # NOME DO ARQUIVO
  nome_arquivo = "1.pdf"
  arquivo = '%s/uploads/%s' % (settings.MEDIA_ROOT, nome_arquivo)

  if os.path.isfile(arquivo):
   # REDIRECT CASO NÃO ENCONTRAR O ARQUIVO
   return redirect('/')

  imagem =  '%s/%s' % (settings.MEDIA_ROOT, "sua_imagem_aqui.jpg")

  # CRIAÇÃO DO PDF EM MODO PAISAGEM , TAMANHO A4
  c = canvas.Canvas(arquivo, pagesize=landscape(A4))
  c.drawImage(
   '%s' % imagem,
   0,
   0,
   29.7*cm,
   21*cm
  )

  # DEFINIÇÃO DE FONTE, FAMILIA, TAMANHO E COR
  c.setFont("Helvetica", 16)
  c.setFillColor(HexColor(0x094d8a))

  # ESCRITA DO TEXTO POR CIMA DA IMAGEM COM ALINHAMENTO
  c.drawString(18.4*cm, 14*cm, "%s" % participante.nome)

  # GERAÇÃO E CRIACAO DO PDF
  c.showPage()
  c.save()

  # REDIRECT PARA VIEW QUE FORCARÁ O DOWNLOAD
  return redirect('certificados:download',participante.id)

 def get(self, request, *args, **kwargs):
  return redirect('/')


#############################################################
# DOWNLOAD
#############################################################
class ForceDownload(View):
 def get(self, request, *args, **kwargs):
  from django.http import HttpResponse
  from os import path
  
  import mimetypes

  arquivo = '%s/uploads/%s.pdf' % (settings.MEDIA_ROOT, kwargs['pk'])

  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 # Create your views here.


E no urls deixe da seguinte forma:


# coding: utf-8
from django.conf.urls import patterns, include, url
from . import views

urlpatterns = patterns('',

 ############################################################################
 # DOWNLOADS
 ############################################################################
 url(r'^downloads/(?P<pk>\d+)/$', views.ForceDownload.as_view(), name='download'),

 ############################################################################
 # CERTIFICADO
 ############################################################################
 url(r'^(?P<slug>[-\w]+)/$', views.PDFView.as_view(), name='pdf_detail'),


)

hasta!

quarta-feira, 2 de julho de 2014

Como fazer a contrab trabalhar pra você

Normalmente quando é necessário uma tarefa repetitiva e que possui um certo grau de integração com outros serviços, utilizo o recurso da contrab.

No python basta criar seu arquivo e definir nele o que será feito. Em seguida basta agendar a tarefa na crontab de acordo com a periodicidade necessária.

Para listar as tarefas agendadas na cron basta executar o comando:
crontab -l

Para criar/editar tarefas basta executar o comando:
crontab -e

Vale ressaltar que caso nao goste do editor que a cron utiliza, pode trocar por algum  de sua preferencia, como o nano, basta executar o seguinte comando:

export VISUAL=nano

Para definir o tempo que você pode fornecer valores para minutos, horas, dias do mes, meses e dias da semana. Nesta ordem. Também é possível definir * para qualquer um destes parametros de forma a referenciar qualquer valor.

Outra coisa que vale dizer é : Se vc precisa executar uma rotina que precisa de mais de um comando , certifique-se que todas as linhas sejam aglutinadas em apenas uma, através do &&.

Exemplo:

# m h  dom mon dow   command

0 * * * 1,2,3,4,5 . /ENV/bin/activate && python carga.py && deactivate

O comando acima roda sempre que os minutos forem iguais a 0, para todas a horas, em todos os dias do mês, durante todos os meses e somente de segunda a sexta. Ele inicia o  ambiente virtual, executa o arquivo carga.py e desativa o ambiente virtual.

quarta-feira, 7 de maio de 2014

Paginação estilo Twitter com Django CBV e django-endless-pagination



Quem já não precisou fazer uma paginação ao estilo do twitter? Bom não é complicado. Pelo menos não com as dicas abaixo!

Requisitos necessários:

  • Python >= 2.6
  • Django >= 1.3
  • jQuery >= 1.7


Instalação:
pip install django-endless-pagination

Configuração:


Adicione a app na setting INSTALLED_APPS no settings.py:
...
'endless_pagination',
...

Adicione a linha abaixo na setting TEMPLATE_CONTEXT_PROCESSORS também no settings.py:
...
'django.core.context_processors.request',
...

Na views.py

from django.shortcuts import render, render_to_response, get_object_or_404
from django.template import Context, loader, RequestContext
from .models import Produto

class ProdutoTTPag(View):
 def get(self, request, *args, **kwargs):

  template = 'produtos/lista-produtos.html'
  page_template = 'produtos/paginacao.html'

  produtos = Produto.objects.filter(ativo=True)
  
  context = {
   'page_template': page_template,
   'produtos_list' : produtos,
  }

  if request.is_ajax():
   template = page_template

  return render_to_response(template, context, context_instance=RequestContext(request))


No urls.py

Adicione a linha abaixo:
...
url(r'^(?P[-\w]+)/$', views.ProdutoTTPag.as_view(), name='produtos'),
...


No template:

Aqui será necessário a criação de dois arquivos html. Um para ser de fato a lista (lista-produtos.html) e o outro para ser apenas os itens, para que o ajax possa trazê-los de forma correta (paginacao.html).

lista-produtos.html:
...
{% load endless %}
...

{% block extra_js %}
    <script src="{{ STATIC_URL }}endless_pagination/js/endless-pagination.js" type="text/javascript"></script>
    <script type="text/javascript">
     jQuery(document).ready(function($) {
      //$.endlessPaginate({
         //    paginateOnScroll: true,
         //    paginateOnScrollChunkSize: 5,
         //    paginateOnScrollMargin: 200
         //});

      $.endlessPaginate({});
     });
    </script>
{% endblock extra_js %}

...
<section class="list-products">
 <ul>
  {% include page_template %}
 </ul>
...
</section>

Aqui a parte comentada serve para trazer os resultados das outras páginas conforme o scroll da página.

paginacao.html:

{% load endless %}

{% paginate 9 produtos_list %}
{% for p in produtos_list %}
 <li>
  {# HTML PARA ITEM DO PRODUTO #}
 </li>
{% endfor %}
{% show_more %}

Mais informações em:

  1. http://django-endless-pagination.readthedocs.org/en/latest/index.html
  2. https://github.com/frankban/django-endless-pagination
  3. https://pypi.python.org/pypi/django-endless-pagination/2.0


hasta!

sábado, 26 de abril de 2014

Instalação do Vagrant no Windows com instalador MSI

Instalar o vagrant no windows agora ficou muito mais fácil. Diferente de todos os passos vistos em Instalação do Vagrant no windows, agora tem um instalador.

Tentei instalar seguindo os passos do tutorial anterior e recebi uma mensagem de aviso dizendo que o Vagrant agora não era mais recomendado baixar como uma ruby gem, e esta não terá mais suporte nem atualizações. Ainda é possível instalar segundo os passos da mensagem, mas este não é o objetivo deste tutorial.

Vamos lá.

  1. Baixe e instale o Oracle Virtual Box no link https://www.virtualbox.org/wiki/Downloads
  2. Adicione o caminho da instalação no PATH do windows.
  3. Baixe e instale o instalador para sua windows no link http://www.vagrantup.com/downloads
  4. Crie uma pasta chamada vagrant-machine no disco C (C:) para facilitar o acesso via prompt.
  5. Abra o promt de comando (cmd) e acesse a pasta recém criada:
    1. cd c:\vagrant-machine
  6. Execute os comandos:
    1. vagrant init hashicorp/precise32
      1. Este comando criará o Vagrantfile
    2. vagrant up
      1. Este comando colocará a maquina virtual em execução
    3. sudo apt-get install libxml2-dev libxslt1-dev python-libxml2 python-setuptools git-core build-essential libxml2-dev libpcre3-dev libpcrecpp0 libssl-dev zlib1g-dev libgeoip-dev memcached libmemcached-dev python-mysqldb libmysqlclient16-dev python-virtualenv
    4. sudo apt-get update
    5. sudo apt-get install python-virtualenv
    6. sudo apt-get build-dep python-imaging
    7. sudo sh postinstall.sh
    8. Abra o arquivo Vagrantfile dentro de C:\vagrant-machine e descomente a linha
      1. config.vm.network "forwarded_port", guest: 80, host: 8080
    9. Adicione abaixo portas extras
      1. config.vm.network "forwarded_port", guest: 8000, host: 8000
      2. config.vm.network "forwarded_port", guest: 8001, host: 8001
      3. config.vm.network "forwarded_port", guest: 8002, host: 8002
    10. Adicione abaixo de
      # config.vm.synced_folder "../data", "/vagrant_data":
      1.  
        config.vm.synced_folder "../wamp/www", "/projetos"
    11. sudo apt-get install git
    12. Crie o ENV 
      1. virtualenv --no-site-packages --unzip-setuptools django16
    13. Ligar o ENV
      1. . django16/bin/activate
    14. Instale primeiro o driver do MySQL que é o que dá mais trabalho:
      1. sudo apt-get build-dep python-mysqldb
      2. sudo pip install MySQL-python
    15. Alguns aplicativos uteis:
      1. BeautifulSoup==3.2.1
      2. Django==1.6.3
      3. Fabric==1.8.3
      4. MySQL-python==1.2.5
      5. PIL==1.1.7
      6. Pillow==2.4.0
      7. South==0.8.4
      8. argparse==1.2.1
      9. distribute==0.6.24
      10. django-appconf==0.6
      11. django-ckeditor-updated==4.2.8
      12. django-compressor==1.3
      13. django-localflavor==1.0
      14. django-pagination==1.0.7
      15. django-simple-captcha==0.4.2
      16. django-subdomains==2.0.4
      17. easy-thumbnails==2.0.1
      18. ecdsa==0.11
      19. paramiko==1.12.3
      20. pycrypto==2.6.1
      21. simplejson==3.4.0
      22. six==1.6.1
      23. sorl-thumbnail==11.12.1b
      24. wsgiref==0.1.2
    16. Salve esta lista num arquivo txt(requirements.txt) e execute o comando:
      1. pip install -r requirements.txt

quarta-feira, 16 de abril de 2014

error: command 'cc' failed with exit status 1

Problemas para instalação das libs do python no ENV no Mavericks?

Com o ENV ligado, se a instalação de algum pacote apresentar o seguinte erro:

error: command 'cc' failed with exit status 1

Execute estas duas linhas no seu shell:

export CFLAGS=-Qunused-arguments

export CPPFLAGS=-Qunused-arguments


Essas exportações dizem ao compilador para ignorar argumentos não utilizados, em vez de reclamar sobre eles.

A razão parece ser que Python compila módulos usando as opções com que ele foi construído, exceto uma dessas opções não funciona mais em mavericks.

Agora é só instalar suas libs normalmente com o pip.


hasta!

quinta-feira, 10 de abril de 2014

Como fazer um filtro personalizado pro admin do Django com o SimpleListFilter

Muitas vezes os filtros automáticos que o admin do django faz são muito úteis. Contudo há momentos que simplesmente colocar o nome do atributo no list_filter não atende. Pra esses momentos temos o SimpleListFilter. 

Ano de Copa, álbuns de figurinhas à venda, suponhamos que, assim como eu, você tenha feito (ou queira fazer)  um sistema pra gerenciamento das figurinhas da Panini.

O models.py ficaria assim:

# coding: utf-8
from django.db import models
class Figurinha(models.Model):
 """(Figurinha description)"""
 numero = models.CharField(max_length=3, verbose_name=u'Número')
 quantidade = models.IntegerField(default=0)
 especial = models.BooleanField(default=False, help_text='Figurinhas brilhantes e/ou diferenciadas')
 data = models.DateTimeField(null=True, blank=True, auto_now=True, verbose_name=u'Modificação')

 class Meta:
  ordering = ('id',)

 def __unicode__(self):
  return self.numero



Algumas explicações antes de continuarmos:

  • Número é sim um CharField, pois neste álbum existem figurinhas alfanuméricas (J1, J2, J3, J4, L1, L2, L3, L4 e W1)
  • Quantidade será o campo atualizável, onde 0 são as figurinhas que faltam, 1 pra colada no álbum e maiores que 1 pra quantidade de repetidas. Ex: Quantidade = 2, são 1 no álbum e 1 repetida.
  • Data será atualizada a cada atualização da figurinha para que seja possível emitir a data da ultima atualização da lista

E o admin.py :

class StatusListFilter(admin.SimpleListFilter):
 # Human-readable title which will be displayed in the
 # right admin sidebar just above the filter options.
 title = 'Status'

 # Parameter for the filter that will be used in the URL query.
 parameter_name = 's'

 def lookups(self, request, model_admin):
  """
  Returns a list of tuples. The first element in each
  tuple is the coded value for the option that will
  appear in the URL query. The second element is the
  human-readable name for the option that will appear
  in the right sidebar.
  """
  return (
   ('falta', 'Falta'),
   ('tenho', 'Tenho'),
   ('repetida', 'Repetida'),
  )

 def queryset(self, request, queryset):
  """
  Returns the filtered queryset based on the value
  provided in the query string and retrievable via
  `self.value()`.
  """
  # Compare the requested value (either '80s' or 'other')
  # to decide how to filter the queryset.
  if self.value() == 'falta':
   return queryset.filter(quantidade=0)
  elif self.value() == 'tenho':
   return queryset.filter(quantidade__gt=0)
  elif self.value() == 'repetida':
   return queryset.filter(quantidade__gt=1)

class FigurinhaAdmin(admin.ModelAdmin):
 search_fields = ('numero',)
 list_display = ('numero','quantidade','especial','data')
 list_filter = ['quantidade','especial','data',StatusListFilter]
 list_editable = ['quantidade',]
 date_hierarchy = 'data'
 readonly_fields = ['numero','especial',]
 save_on_top = True

 fieldsets = (
  (u'Número', {'fields': ('numero',)}),
  ('Quantidade', {'fields': ('quantidade',)}),
  ('Especial', {'fields': ('especial',)}),
 )

admin.site.register(Figurinha, FigurinhaAdmin)


Para mais informações sobre o SimpleListFilter, consulte https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter

hasta!

quinta-feira, 20 de março de 2014

Can't compare offset-naive and offset-aware datetimes

Usando um ambiente com o Django 1.4.3 e  o django-watermark 0.1.6-pre1 o erro :

CAN'T COMPARE OFFSET-NAIVE AND OFFSET-AWARE DATETIMES

Para resolver basta puxar a app watermark para dentro do seu projeto ao invés de usar a instalação do ENV e fazer as seguintes alterações no arquivo watermarker/templatetags/watermark.py:




Na linha 9: Adicione a linha :

from django.utils import timezone




Na linha 155/156: Troque a linha:

if modified >= watermark.date_updated:


Pela linha:

if timezone.make_aware(modified, timezone.get_default_timezone()) >= watermark.date_updated:



hasta!