Mostrando postagens com marcador Admin. Mostrar todas as postagens
Mostrando postagens com marcador Admin. Mostrar todas as postagens

sexta-feira, 12 de agosto de 2016

Plugins Úteis: django-image-cropping - Como incoporar uma ferramenta de recorte para fotos no admin


Imagine que temos um projeto onde o usuário, responsável por alimentar os conteúdos, não tem a mínima noção do tamanho da imagem necessária para não destruir o layout, e nenhum pouco de boa vontade para ler a especificação do tamanho no help_text?

Claro que sempre dá pra fazer o recorte automático com o sorl-thumbnail, mas e se o usuário quiser escolher como recortar a foto?

Bom, pra isso, apresento-lhes o impressionante : django-image-cropping.


Vejamos como utilizar:

1. Primeiramente, instale ele no seu virtualenv:

pip install django-image-cropping

2. Se não tiver o easy_thumbnails instalado, instale:

pip install easy_thumbnails 

3. Adicione os dois no INSTALLED_APPS:

INSTALLED_APPS = [
    ...
    'easy_thumbnails',
    'image_cropping',
    ...
]

4. Adicone também no settings.py:

from easy_thumbnails.conf import Settings as thumbnail_settings
THUMBNAIL_PROCESSORS = (
    'image_cropping.thumbnail_processors.crop_corners',
) + thumbnail_settings.THUMBNAIL_PROCESSORS

5. No seu model que quiser a função de recorte no admin deixe como a seguir:

from image_cropping import ImageRatioField

class SeuModel(models.Model):
    ...
    imagem = models.ImageField(upload_to="/caminho/para/upload/",)
    cropping = ImageRatioField('imagem', '900x900')
    ...


Mude a proporção do atributo cropping de acordo com sua necessidade.

6. No admin.py:

from django.contrib import admin
from image_cropping import ImageCroppingMixin

class SeuModelAdmin(ImageCroppingMixin, admin.ModelAdmin):
    pass

admin.site.register(SeuModel, SeuModelAdmin)

7. No template que for exibir a foto recortada utilize a tag provida pelo plugin:

{% cropped_thumbnail instancia_do_seu_model "cropping" [scale=INT|width=INT|height=INT|max_size="INTxINT"] %}

EX:
<img cropping="" scale="0.5" src="{% cropped_thumbnail instancia_do_seu_model " />


8. Dá inclusive para utilizar esse plugins para Inlines:


from image_cropping import ImageCroppingMixin
class ImagemInline(ImageCroppingMixin, admin.TabularInline):
 model = Imagem
 extra = 0



Desta maneira, ao fazer o upload, o usuário poderá selecionar a área de recorte diretamente no admin, respeitando a proporção imposta no models.py e sem destruir o layout.


Fonte e mais informações: https://pypi.python.org/pypi/django-image-cropping


hasta!

quarta-feira, 20 de abril de 2016

Como esconder alguns registros do changelist do admin do Django



A pergunta é simples: Pra que eu um dia iria precisar esconder alguns registros do change list, se já estou no admin como superuser?

Bom, imagine que seu cliente quer o acesso ao admin para gerenciar os conteúdos e também acesso a alguma seção do projeto que o login é necessário.

Quão surpreso você ficaria se descobrisse, que aquele seu cadastro de teste onde vc conseguia entrar para ajudar, testar e acompanhar o andamento do projeto fosse removido?

Isso, apesar de ridículo, não é de todo o impossível, e foi por passar por algo semelhante que escrevo este post.


Para ocultar os registros de uma determinada classe, basta  sobrescrever o método get_queryset do admin daquela classe no admin.py:

class CadastroAdmin(admin.ModelAdmin):
 form = CadastroForm
 search_fields = ('nome',)
 list_display = ('nome', 'email', 'unidade','ativo',)
 list_filter = ['ativo','unidade']
 list_editable = ['ativo',]
 exclude = ('user',)
 save_on_top = True


 def get_queryset(self, request):
  qs = super(CadastroAdmin, self).get_queryset(request)
  if request.user.is_superuser:
   return qs
  return qs.exclude(id__in=[13,14,15])

admin.site.register(Cadastro, CadastroAdmin)

No exemplo acima, quando o usuário logado for superuser do admin, este verá todos os registros, do contrário, a queryset excluirá dos resultados os cadastros com ids 13, 14 e 15.

Com pequenos ajustes, este método tornar bastante útil para evitar dedos inquietos clicando onde não devem.


hasta!

sexta-feira, 25 de setembro de 2015

Plugins Úteis: django-geoposition - Como incorporar o google maps dentro do admin para geolocalização

Precisa incorporar um mapa com base em um endereço no administrativo para exibir no front? Tarefa simples pro django-geoposition (https://github.com/philippbosch/django-geoposition).

A instalação é simples:
pip install django-geoposition

Coloque a linha abaixo no seu arquivo settings.py, em INSTALLED_APPS:
INSTALLED_APPS = (
    ...
    'geoposition',
    ...
)

Outra configuração que vale a pena fazer, é incluir no seu arquivo settings.py as linhas abaixo para definir o zoom:
GEOPOSITION_MAP_OPTIONS = {
    'minZoom': 15,
    'maxZoom': 18,
}

No seu arquivo models.py, deixe como a seguir:
from geoposition.fields import GeopositionField
from localflavor.br.br_states import STATE_CHOICES

class SuaClasse(models.Model):
 """(Unidade description)"""
 endereco = models.CharField(max_length=255, verbose_name=u'Endereço', help_text='Para uma melhor localização no mapa, preencha sem abreviações. Ex: Rua Martinho Estrela,  1229') 
 bairro = models.CharField(max_length=255,)
 cidade = models.CharField(max_length=255,help_text="Para uma melhor localização no mapa, preencha sem abreviações. Ex: Belo Horizonte")
 estado = models.CharField(max_length=2, null=True, blank=True,choices=U.STATE_CHOICES)
 position = GeopositionField(verbose_name=u'Geolocalização', help_text="Não altere os valores calculados automaticamente de latitude e longitude")

 class Meta:
  verbose_name, verbose_name_plural = u"Sua Classe" , u"Suas Classes"
  ordering = ('endereco',)

 def __unicode__(self):
  return u"%s" % self.endereco 

No administrativo será gerado tudo automático, mas existem algumas melhorias que podem ser feitas pra ficar ainda mais bacana. Inclua o arquivo css e js abaixo que em seguida explico como faremos.
# coding: utf-8
from django import forms
from django.contrib import admin
from .models import *


class SuaClasseForm(forms.ModelForm):
 class Media:
  css = {
   'all': ('admin/css/geoposition_override.css',)
  }
  js = ('admin/js/geoposition_override.js',)

class SuaClasseAdmin(admin.ModelAdmin):
 form = SuaClasseForm
 search_fields = ('endereco', 'cidade',)
 list_display = ('endereco', 'cidade','estado','bairro')
 list_filter = ['estado',]
 save_on_top = True



admin.site.register(SuaClasse, SuaClasseAdmin)

No arquivo css adicionado (geoposition_override.css), iremos ocultar o campo de busca do mapa, e utilizaremos nossos próprios atributos da classe para tal, mesmo porquê, o atributo position irá só gravar em banco a latitude e longitude e não o endereço pesquisado.

Crie um arquivo dentro de <STATIC_DIR>/admin/css, chamado geoposition_override.cssm, e nele coloque simplemente a linha abaixo:

.geoposition-search input{display:none;}

Agora, crie um js chamado geoposition_override.js na pasta <STATIC_DIR>/admin/js com as linhas abaixo:
django.jQuery(document).ready(function($) {
 $('#id_position_0, #id_position_1').attr('readonly', 'readonly');

 $('#id_endereco, #id_cidade, #id_estado').blur(function(event) {
  /* Act on the event */
  if ($('#id_endereco').val()!='' && $('#id_cidade').val()!='' && $('#id_estado').val()!='') {
   $('.geoposition-search input').val($('#id_endereco').val()+' ' +$('#id_cidade').val()+' '+$('#id_estado').val());
   
   // TRIGGER DO ENTER PARA EXECUTAR A BUSCA
   var e = $.Event("keydown");
   e.which = 50; // # Some key code value
   $(".geoposition-search input").trigger(e);
  };
 });
});

E o resultado:

hasta!

quinta-feira, 22 de janeiro de 2015

Validações customizadas no forms.ModelForm com método clean para um atributo


As vezes alguns campos requerem validações além do tipo de dados neles inserido. Abaixo tem um exemplo que fiz para um caso desse.

A necessidade era validar um charfield de acordo com uma série de valores e por ser campo aberto não poderia fazer um choices.


models.py
class SuaClasse(models.Model):
 ...
 seu_atributo = models.CharField(max_length=20)
 ...

admin.py
from django.core.exceptions import ValidationError
import re

class SuaClasseAdminForm(forms.ModelForm):
 class Meta:
  model = SuaClasse

 def clean_seu_atributo(self):
  cleaned_data = super(SuaClasseAdminForm, self).clean()
  seu_atributo = cleaned_data.get("seu_atributo")
  if not seu_atributo in ['TL','TR','BR','BL','C','R']:
   m = re.search('[0-9]*(%)*x[0-9]*(%)*', seu_atributo)
   if not m:
    raise ValidationError("Preencha o atributo com uma das opções disponíveis.")

class SuaClasseAdmin(admin.ModelAdmin):
 form = SuaClasseAdminForm

 ...

No exemplo acima, preciso que o valor de seu_atributo seja um dos valores contidos na lista ['TL','TR','BR','BL','C','R'] ou respeite a expressão regular que testa para os seguintes exemplos: 300x200, 50%x300, 40x90% ou 150x400.

O que podemos notar é que o método clean_seu_atributo fará a validação no campo especificado e trará o erro logo acima do campo em caso de falha. Também é possivel fazer somente o método clean, contudo o erro será mostrado no início do form, sem vínculo a campo algum.


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, 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!

sexta-feira, 23 de agosto de 2013

Ordenando por um campo calculado por uma def no admin

Seguindo o exemplo anterior, Como utilizar os inlines no front para os ModelForms (class based view) , imagine que gostaríamos de exibir quantas fotos cada cadastro postou. Fácil né?

Basta fazer uma def no models.py como abaixo e depois colocá-la no list_display do admin.py:

def qtde_fotos(self):
    return self.foto_set.all().count()


Mas e se, quiséssemos ordenar no admin por este valor? Saber em ordem quais os cadastros que mais enviaram fotos? Por ser uma def, o django não ordena automaticamente. Pra isso temos que fazer alguns ajustes. Primeiro de tudo, apague esta def do seu model caso tenha feito.

No admin de seu model no arquivo admin.py, deixe como abaixo:


def queryset(self, request):
    qs = super(CadastroAdmin, self).queryset(request)
    qs = qs.annotate(qtde=Count('foto'))
    return qs

def qtde_fotos(self, inst):
    return inst.qtde
qtde_fotos.admin_order_field = 'qtde'


depois basta adicionar a def qtde_fotos no list_display.


hasta!

sexta-feira, 21 de junho de 2013

Exibir e ordenar por um campo FK de outra classe no change list

Comumente utilizamos classe com FKs e no change list do admin existe a possibilidade de fazer filtros por esses campos da seguinte forma:

list_filter = ['suafk__seuatributo']

Sabia que tem como fazer isso ser exibido também no list_display?

Se tentarmos utilizar da mesma forma surge o seguinte erro:

ImproperlyConfigured at /admin/seu-app/sua-classe/
Sua-ClasseAdmin.list_display[4], 'suafk__seuatributo' is not a callable or an attribute of 'Sua-ClasseAdmin' or found in the model 'Sua-Classe'.

O numero 4 indica a posição que colocou o atributo a ser exibido, e pode variar de acordo com a posição que colocar.

Mas então como fazer isso? Simples:

No seu models.py crie um método dentro da classe que tem a FK do atributo que deseja listar da seguinte forma:

def seu_metodo(self):
    return self.suafk.seuatributo
seu_metodo.admin_order_field = 'suafk__seuatributo'


Agora basta chamar o metodo recem criado no list_display:

list_display = ('seu_metodo')


hasta!

quinta-feira, 23 de agosto de 2012

Personalizando o template Inline de um model

Para colocar um template personalizado no seu inline, basta adicionar atributo template no seu Inline, como no exemplo abaixo:

class FotoInline(admin.TabularInline):
    template = 'admin/galeria/edit_inline/tabular.html'
    model = Foto
    extra = 5


hasta!

terça-feira, 7 de fevereiro de 2012

Filtrar apenas os usuários staff no admin

Quando utilizamos a autenticação provida pelo django, um problema é que sempre que entramos no change list do Auth User, lá tem todos os usuários que podem fazer login, tanto no front quanto no admin.

Para isso basta colocar o código abaixo em qualquer arquivo admin.py:


from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User

class StaffAdmin(UserAdmin):
"""
Esta classe recria as propriedades do admin do model auth.User
"""
list_filter = ( 'is_active', 'is_superuser' )
date_hierarchy = 'date_joined'
save_on_top = True

def queryset(self, request):
qs = super( UserAdmin, self ).queryset( request )
qs = qs.exclude( is_staff=False )
return qs


admin.site.unregister( User )
admin.site.register( User, StaffAdmin )


Se ainda preferir deixar separado, pode criar um arquivo admin.py na raiz do projeto e incluir o nome da pasta ( fornecido no startproject ) no INSTALLED_APPS.

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!


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

segunda-feira, 29 de novembro de 2010

Widget para many to many field interessante

Normalmente quando se faz um many to many, é gerado no admin do django um select com a opção multiple. Porém para quando este caso tem bastante registro, a usabilidade não fica das melhores. Até encontrar um item que procura na lista vai tempo.

Para resolver esse problema adicione a linha abaixo no seu Model Admin:

filter_horizontal = ('nome_do_campo_m2m',)

Desta forma este campo passará ter as mesma interface/usabilidade do esquema de permissões do módulo de usuários do django.

hasta!

segunda-feira, 24 de agosto de 2009

Novos recursos do Admin - actions



Quando é necessário fazer uma atualização com mais um registro? Entrar um a um, editar e salvar? Existe um meio mais prático e eficiente pra fazer tais tarefas repetitivas.

Eis que surge o actions. Na versão do trunk do Django ele já vem nativo com a opção remover todos os registros selecionados, muito útil quando era preciso apagar vários ao mesmo tempo.

Essa nova funcionalidade não para por aqui. Também é possível colocar ações customizadas dentro desse fantástico recurso. Vejamos como.

Vejamos um exemplo:

Muitos os portais de conteúdo possuem a funcionalidade de colocar um determinado conteúdo, uma nóticia por exemplo, em destaque. Para isso no seu módulo de notícia, provavelmente terá o campo:

destaque = models.BooleanField(default=False)


Suponhamos que seja necessário colocar 5 noticias em destaque. Entrar uma a uma, não é uma opção, porquê como sempre digo, mais que dois é muito. Vejamos como ficaria de uma forma eficiente.

Dentro do seu admin.py, vá até a classe do admin do módulo que deseja implementar o actions, NoticiaAdmin por exemplo, e crie já as duas funções:





Note que não é necessário criar o remover selecionado, pois ele já é nativo.


A coisa toda acontece na linha 28. Perceba que não é necessário correr um for para pegar todas as notícias selecionadas. Ele simplesmente faz o update em todos os objetos de notícia que forem selecionados através do queryset.


Isto pode ser feito para atualizações em massa, duplicações, e quaisquer outros recursos que conseguir pensar para um conjunto de dados do mesmo tipo.


hasta!

Novos recursos do Admin - date_hierarchy


O date_hierarchy já funciona apartir da versão 1.0 e proporciona um filtro muito útil para a listagem dos dados de algum módulo. Ele monta uma estrutura para navegação pelas datas dos registro ali listados.

Para utilizá-lo é bem simples. Qualquer classe que possua um campo do tipo DateField pode fazer uso do mesmo. Basta colocar a seguinte linha dentro da classe do admin do seu model, dentro do admin.py

date_hierarchy = ('data')

Onde 'data' é o nome do seu atributo.

Note que ao fazer isso, logo acima da listagem dos dados vai surgir alguns links com os anos que possuem conteudo dentro daquele módulo. Ao clicar no ano, aparecerão os meses e posteriormente os dias que possuem algum conteúdo.




hasta!