Django + Oracle + TextField + ForeignKey: contornando problema em realizar distinct em campo CLOB

251 views
Skip to first unread message

João Olavo Baião de Vasconcelos

unread,
Mar 19, 2009, 11:21:37 AM3/19/09
to django-brasil
Olá pessoal!

Eu enfrentei um problema [1] ao ter um modelo com um TextField e um
campo foreignkey ou manytomanyfield armazenados em um BD Oracle.

O problema ocorre quando eu tento realizar uma busca e o campo com
chave estrangeira está incluído na busca (incluído na variável
search_field no admin.py). Aparece a mensagem de erro "*DatabaseError:
ORA-00932: inconsistent datatypes: expected - got CLOB*". Isso pq,
quando tem uma chave estrangeira na busca, o django insere um DISTINCT
no select do sql gerado [2], só que o oracle não suporta SELECT
DISTINCT em campos CLOB (que é como um TextField é armazenado).

Bom, pra contornar isso, a melhor maneira que eu achei foi criar um
field TextField personalizado que, em vez de armazenar os dados em uma
coluna CLOB, armazena em um VARCHAR2. O problema que estou enfrentando
é que não estou conseguindo mostrar uma mensagem de erro quando alguém
insere mais que 4000 chars (capacidade máxima de um VARCHAR2) e salva
o objeto. O objeto acaba sendo salvo sem mostrar msg de erro.

Vejam como está o código: http://dpaste.com/hold/16484/

Onde estou errando? Mesmo que eu tire o if do método clean(), deixando
levantar a exceção independente do que foi inserido, a msg não
aparece...

Outra maneira para contornar esse problema seria só realizar um SELECT
DISTINCT em campos estrangeiros, e não em campos "locais". Ou seja, em
[2], ao invés de fazer "qs = qs.distinct()" e afetar todos os SELECTs
gerados (incluindo aqui os TextFields), afetar somente os SELECTs
feitos em outras tabelas, ficando de fora os campos CLOB. Mas eu não
olhei como é a estrutura desse objeto "qs" pra saber se é possível
definir internamente em que campo será feito DISTINCT e em que campo
não será. Creio que essa seja a melhor solução, pois evitaria soluções
técnicas para contorno de adversidades (vulgo "gambiarra").

Valeu!!

[1] http://groups.google.com/group/django-users/browse_thread/thread/cd6b14ede0980131
[2] http://code.djangoproject.com/browser/django/trunk/django/contrib/admin/views/main.py?rev=7967#L225

--
João Olavo Baião de Vasconcelos
Bacharel em Ciência da Computação
Analista de Sistemas - Infraestrutura
joaoolavo.wordpress.com

SleX Luthor

unread,
Mar 19, 2009, 4:04:03 PM3/19/09
to django...@googlegroups.com
já pensou em fazer uma VIEW no oracle e depois acessar ela?


CREATE VIEW TESTE AS
  SELECT DISTINCT CAMPO
  FROM TABELA;

?


2009/3/19 João Olavo Baião de Vasconcelos <joao...@gmail.com>



--
Alexandre Villela Eiras Brandão de Oliveira
or simply "SleX"

"Dispõe o Eterno Escriba e, havendo escrito, a folha vira. E não há ciência ou devoção que apague uma linha. E não há pranto sofrido que risque uma palavra. Ah, todo choro é vão!" (Omar Khayyam no livro Rubayat)

João Olavo Baião de Vasconcelos

unread,
Mar 19, 2009, 4:56:20 PM3/19/09
to django...@googlegroups.com
2009/3/19 SleX Luthor <sx....@gmail.com>
já pensou em fazer uma VIEW no oracle e depois acessar ela?

Desculpe-me a ignorância, mas... criar essa view com qual objetivo? Pq que com isso eu não terei o problema citado?
E ainda... como o django irá usar essa view?

Valeu!!
 

Sergio Durand

unread,
Mar 20, 2009, 8:49:02 AM3/20/09
to django...@googlegroups.com
João Olavo Baião de Vasconcelos escreveu:
> 2009/3/19 SleX Luthor <sx....@gmail.com <mailto:sx....@gmail.com>>

>
> já pensou em fazer uma VIEW no oracle e depois acessar ela?
>
>
> Desculpe-me a ignorância, mas... criar essa view com qual objetivo? Pq
> que com isso eu não terei o problema citado?
> E ainda... como o django irá usar essa view?
>
> Valeu!!
>

Oi João,

Sobre o fato de "como o django irá usar essa view" eu precisei fazer
isso esta semana, mas com o postgresql.
Basicamente o django não vai fazer diferença se é uma tabela ou uma
view. Ele simplesmente vai executar, por exemplo, um "SELECT * FROM
cliente_cliente" e aí o problema é do banco de dados de como irá
retornar os dados.

No caso eu criei uma view com a mesma estrutura da tabela "real" (que na
verdade tem outro nome).
No models.py você teria que colocar a opção managed = False na classe
Meta (para o django não criar a tabela no syncdb).

Até aí você teria metade o problema resolvido... o django iria consultar
a sua view como se fosse uma tabela real.
A outra metade do problema é que não tem como você dar um
insert/update/delete na view (pelo menos no postgresql não... também não
sei como seria o caso numa view materializada). Mas enfim.... eu tive
que criar uma RULES (que é praticamente um primo da trigger) para que
caso ocorra insert/update/delete ele não faz nada na view e executa
essas operacoes na tabela "real".

Bom... caso você venha precisa usar view's o caminho das pedras será
mais ou menos este =)

Abraços,
Sérgio Durand

João Olavo Baião de Vasconcelos

unread,
Mar 20, 2009, 9:22:08 AM3/20/09
to django...@googlegroups.com
2009/3/20 Sergio Durand <dja...@durand.eti.br>
Basicamente o django não vai fazer diferença se é uma tabela ou uma view. Ele simplesmente vai executar, por exemplo, um "SELECT * FROM cliente_cliente" e aí o problema é do banco de dados de como irá retornar os dados.

Blz, Sergio! Entendi...

Só não entendi ainda como essa view irá solucionar o problema de não poder dar um "select distinct" em um campo clob, já que o view sugerido pelo Slex faz justamente um 'select distinct'. =)

Valeu!!
--
João Olavo Baião de Vasconcelos
Reply all
Reply to author
Forward
0 new messages