Usando a administração do Django, pude criar rapidamente formulários de requerimento para os agentes do CCIW – ao contrário dos longos papéis que eles tinham de preencher todo ano, os dados poderão ser coletados em uma base de dados de modo que no próximo ano isso seja feito com poucos cliques. Para utilizar, os agentes terão de ser usuários do tipo staff na administração automática do Django, o que é tranquilo, desde que eu limite suas permissões para simplesmente criarem novos objetos do tipo ‘Requerimento’ .
Com isso dois problemas apareceram:
- Um comum: o model ”Requerimento ‘ tem uma chave estrangeira ‘User’ — Tenho de setar isso automaticamente, ou os agentes poderão submeter requerimentos em nome de outros. Não muito bom.
- Quando alguém com mais privilégios navega pelos requerimentos, ele, ou ela, deverá poder ver o campo ‘User’ e setar explicitamente se ele é obrigatório. Isso significa que a lista de campos na classe ‘Requerimento.Admin’ precisa ser de alguma maneira dinâmica.
Consegui fazer ambos funcionarem sem criar muitos remendos no Django. Isso só funciona com magic-removal (deve haver algum modo de fazer no trunk, mas provavelmente será mais difícil).
O primeiro é fácil: criar um middleware (chamado ‘ThreadLocals’) que esconde o objeto ‘User’ em um processo local de armazenamento, e uma função para acessar o mesmo. Fica mais ou menos assim:
# cciw/middleware/threadlocals.py import threading _thread_locals = threading.local()
def get_current_user(): return getattr(_thread_locals, 'user', None) class ThreadLocals(object): """Middleware que pega vários objetos do request e os salva num proceso local de armazenamento.""" def process_request(self, request): _thread_locals.user = getattr(request, 'user', None)
Depois adicione o ThreadLocals no fim de sua configuração de middleware, e você poderá acessar o usuário atual de qualquer código python importando e usando a função get_current_user(). Em meu caso, precisei do usuário atual antes de salvar um objeto do tipo ‘Requerimento’, então eu apenas sobescrevi o método save() da classe Requetimento.
O segundo é um pouco mais difícil. Tentei usar um descritor na classe interna Requerimento.Admin. No entanto, isso não funcionou — a classe meta do model não deixou a classe interna ‘Admin’ funcionar como classe interna e instanciá-la — ao invés disso cria uma instância ‘AdminOptions’ com tudo que a classe ‘Admin’ tinha. Com a remoção de um pouco da mágica, e devido ao modo que o Python deixa você mexer numa classe de um objeto depois que ele foi criado, achei o código abaixo que funciona perfeitamente (reduzi drasticamente o número de campos no model ‘Requerimento’, mas você entenderá):
# Atenção: a classe Requerimento chama-se Application # cciw/officers/models.py from django.db import models from django.contrib.auth.models import User from django.db.models.options import AdminOptions import cciw.middleware.threadlocals
class Application(models.Model): # blank=True para administração funcionar quando o agente não estiver preenchido officer = models.ForeignKey(User, blank = True, default = None) full_name = models.CharField(maxlength = 30) address = models.TextField() def save(self): if getattr(self, 'officer_id', None) is None: self.officer_id = threadlocals.get_current_user().id super(Application, self).save() class Admin: fields = ()# we override this later list_display = ('full_name', ) # Nesse ponto, a classe Requerimento e outros objetos na classe tais como Requerimento_meta # e Requerimento_meta.dmin já estão completamente setadas. class ApplicationAdminOptions(AdminOptions): """ Classe usada para substituir AdminOptions pelo model Requerimento """ def _fields(self): user = threadlocals.get_current_user() if user is None or user.is_anonymous(): # nunca deveria chegar aqui! return () else: if user.has_perm('officers.change_application'): # Campos para um usuário com mais privilégios # para poder modificar requerimentos já inseridos return ( (None, {'fields': ('officer', 'full_name', 'address')} ), ) else: # Campos para um usuário 'agente' comum return ( (None, {'fields': ('full_name', 'address')} ), ) fields = property(_fields) # remove a variável com os campos da instância del Application._meta.admin.fields # Muda a class admin para inserir o comportamento criado acima Application._meta.admin.__class__ = ApplicationAdminOptions
E é isso!
Escrito originalmente por Luke Plant.
Traduzido de http://lukeplant.me.uk/blog.php?id=1107301634
Filed under: admin, middleware, threadlocals | Leave a Comment
Tags: admin, middleware, threadlocals
Pesquisar
-
Você esta atualmente visualizando os arquivos do blog Django Django.
No Responses Yet to “Filtrar conteúdo da administração de acordo com o usuário”