regiov / voluntarios

Website voluntarios.com.br
GNU General Public License v3.0
14 stars 13 forks source link

Utilizar vocabulário controlado para cidades no cadastro de voluntários e entidades #34

Closed regiov closed 1 year ago

regiov commented 2 years ago

Hoje estamos usando um campo de texto livre, vulnerável a erros de grafia. O ideal seria ter uma tabela de municípios do Brasil (fonte IBGE) no banco de dados, exibindo um combo dinâmico de acordo com o estado selecionado, e armazenando a chave do município nas tabelas de voluntário e entidade.

Diogojlq commented 1 year ago

Olá @regiov, vou trabalhar nessa issue !

regiov commented 1 year ago

Legal @Diogojlq, já está reservada pra você. Fique à vontade pra interagir por aqui caso queira discutir possíveis soluções. Uma observação importante que não coloquei na issue é que existem no banco hoje vários nomes errados de cidade, então a solução adotada terá que conseguir conviver com essa realidade...

regiov commented 1 year ago

@Diogojlq, seguem alguns detalhes adicionais sobre essa issue: No cadastro de entidades, foi implementado pelo @GBTelles1 há alguns meses atrás o preenchimento automático de cidade/estado com base no CEP através da utilização de um serviço gratuito. Ou seja, neste caso em particular em princípio não há necessidade de se preocupar tanto - assumindo que o serviço continue funcionando corretamente e se mantenha atualizado ao longo do tempo. Porém muitas entidades se cadastraram antes disso, e é possível que existam erros no banco. Seria interessante termos uma estratégia de validação, alguma rotina que pudesse ser chamada periodicamente via linha de comando, por exemplo. Já no caso dos voluntários, não temos nenhuma validação de cidade.

Diogojlq commented 1 year ago

@regiov em relação aos voluntários, está sendo usado um dicionário com as siglas das UFs, eu encontrei um repositório com os nomes dos estados e cidades brasileiras em SQL (https://github.com/chinnonsantos/sql-paises-estados-cidades), seria uma boa solução incluir no banco, remover esse dicionário com as UFs e criar uma lista de seleção dinâmica, ou apenas criar uma validação para o nome da cidade que compara ela com os nomes de cidade por estado no banco, mantendo esse dicionário para seleção do estado ? Também estou testando utilizar uma API para preencher os campos a partir do CEP, assim como foi feito no caso das entidades, inicialmente pensei que poderia ser problemático por precisar criar um campo de CEP, pois já existem muitos registros sem CEP, mas acredito que seja possível solicitar o CEP apenas para preencher os campos de estado e cidade, sem salvar no banco. E em relação aos erros já existentes, até agora só encontrei soluções manuais, como mapear os erros mais comuns de ortografia e criar no banco uma relação com os nomes corretos, mas não sei se seria o ideal.

regiov commented 1 year ago

Oi @Diogojlq, existem várias possibilidades e também não sei ao certo qual seria a melhor. Só não gosto muito da ideia de incluir um novo campo (CEP) apenas para poder usar aquela API. Outra possibilidade a ser considerada é usar a API do IBGE, que é a fonte oficial para esse tipo de dado no Brasil. Pode-se usar o seguinte padrão de chamada para retornar os municípios de um determinado estado: https://servicodados.ibge.gov.br/api/v1/localidades/estados/{UF}/municipios Essa opção tem a vantagem de sempre retornar os dados mais atuais, pois a lista de municípios no país é dinâmica (apesar de não ter mudado desde 2013). Por outro lado tem a desvantagem de ser um serviço governamental, portanto muito sujeito a instabilidade, se bem que isso poderia ser contornado usando uma URL nossa (ex: voluntarios.com.br/uf/{UF}) que encapsularia a chamada ao serviço do IBGE mas que teria uma propriedade de cache com data de expiração longa (6 meses, p. ex). O que acha?

regiov commented 1 year ago

Uma outra abordagem bastante comum em banco de dados seria como você falou, ter uma tabela de municípios, e que também poderia ser abastecida com conteúdo da API do IBGE. Neste caso poderíamos pensar em criar um campo de relacionamento entre a nova tabela e as tabelas que hoje usam município. Isso facilitaria futuras queries, mas tem a desvantagem de manutenção do conteúdo dessas tabelas ao longo do tempo, já que os municípios são dinâmicos, e também é um pouco mais trabalhoso pra implementar. Mas também é uma solução válida. Eu diria que pra gente o mais interessante seria ter mecanismos para validar o conteúdo de municípios que temos hoje e facilitar a vida de quem preenche os formulários. Só não sei bem como fazer essa última parte, pois se trocarmos o campo texto por um dropdown, como ficará a edição de cadastros com erros nos municípios? Enfim, pense em tudo isso e me diga o que acha...

Diogojlq commented 1 year ago

Boa noite @regiov, estou pensando nessa issue como dois problemas distintos: os novos cadastros que estão sujeitos a erros de digitação e os cadastros que já existem porém contém erros. Acredito que a implementação da chamada para a API do IBGE seja um boa solução para o primeiro problema, evitando que existam novos cadastros com erros no futuro. E quanto ao segundo problema, você falou sobre validar o conteúdo de municípios que temos hoje, e como seria um problema fazer isso caso houvesse um dropdown, mas o dropdown já não funcionaria como uma validação ? Não entendo como isso iria dificultar a validação de erros que já existem, e imagino que não iriam ocorrer novos erros, afinal estaríamos usando a API para selecionar os nomes dos municípios. Supondo que meu raciocínio esteja correto, ao implementar a chamada para a API só restaria corrigir os erros que já existem.

regiov commented 1 year ago

Sim, @Diogojlq, seu raciocínio está correto. Podemos ver como duas questões distintas, mas que estão bastante entrelaçadas, pois o fato de haver erros no banco pode influenciar na solução a ser adotada para o primeiro problema. Sem dúvida, se adotarmos o dropdown, resolvemos a questão dos novos cadastros que hoje estão sujeitos a erros. A única coisa é que se alguém for editar o próprio cadastro e se este estiver errado, o município digitado erradamente não irá aparecer no dropdown, certo? Na prática ficará um conteúdo invisível para quem digitou. E o usuário será forçado a escolher novamente um município, mas dessa vez correto. Bom, por mim tudo bem, podemos seguir dessa forma. Quanto à correção de erros no banco, pensando bem, melhor não nos aventurarmos muito nisso. Podemos corrigir erros menores como falta de acentuação, ajuste de maiúsculas e minúsculas. Qualquer coisa muito além disso passa a ser um pouco invasiva. Melhor deixar que o próprio usuário corrija caso venha a editar seu cadastro no futuro. Faz sentido pra você também?

Diogojlq commented 1 year ago

Faz todo sentido @regiov, estou implementando a call para a API, mas me surgiu uma dúvida que pode ser meio boba: o dropdown com os municípios vai substituir o campo de texto para cidade, correto ? Não há um campo específico para município no formulário. Se isso estiver correto, vou apenas inserir o dropdown com os dados da API no local onde atualmente tem o campo de texto para cidade.

regiov commented 1 year ago

Legal, @Diogojlq, acho que é isso sim. Trocar o campo texto por um dropdown. Só acho que devemos tomar cuidado de não pegar o conteúdo do dropdown diretamente do ibge, pois se o serviço tiver algum problema, nosso usuários não vão conseguir cadastrar o perfil de voluntário. Mais seguro implementar alguma forma de buscarmos esses dados por fora periodicamente do ibge e ao carregarmos o conteúdo do dropdown usamos nossa cópia dos dados. Tem várias formas de fazer isso. Fique à vontade pra interagir por aqui se quiser ideias ou precisar de ajuda.

Diogojlq commented 1 year ago

Boa tarde @regiov, estou estudando soluções e testando algumas coisas, e ainda não consegui uma forma de automatizar a call para a API, para popular o banco periodicamente com dados atualizados, você tem alguma sugestão ?

regiov commented 1 year ago

Olá @Diogojlq, claro, posso dar algumas ideias, mas como disse, existem várias formas de fazer. Acho que eu criaria um programa novo em linha de comando (vol/management/commands/atualiza_municipios.py) com toda funcionalidade de buscar todos os municípios de cada estado no serviço do ibge, armazenando os novos e depois descartando eventuais municípios que tenham trocado de nome. Esse script poderá então ser colocado no cron para rodar periodicamente (1x por ano?) ou podendo ser rodado manualmente quando quisermos. Ou seja, as funcionalidades de validação, montagem do dropdown, etc. rodariam com dados locais (não sei se em tabelas ou arquivos texto), previamente obtidos do ibge através desse linha de comando novo. Será que isso ajuda?

Diogojlq commented 1 year ago

Ajuda muito @regiov, estou seguindo por esse caminho, no momento estou travado tentando importar os modelos para o arquivo que vai popular o banco com os dados da API. Já pesquisei bastante e tentei algumas coisas, mas não paro de receber o erro "ModuleNotFoundError: No module named 'vol' ".

regiov commented 1 year ago

Salve, @Diogojlq. Posso tentar olhar seu código, se quiser. É só dar commit no seu fork e me avisar qual é o arquivo. Mas tá parecendo problema de "path". Se você estiver testando algum linha de comando novo, tem que ver de onde você está tentando rodar ele. Tem que ser no diretório principal, onde está o manage.py. Algo do tipo: "python manage.py meu_linha_de_comando"

Diogojlq commented 1 year ago

Poxa, era isso mesmo, eu estava tentando rodar o arquivo apenas, para testar, quando rodei por terminal utilizando manage.py funcionou, obrigado pela ajuda. Estou agora tentando salvar os dados no banco para depois partir, finalmente, para o dropdown.

Diogojlq commented 1 year ago

Olá @regiov, estou quase conseguindo finalizar essa issue, no momento estou tentando retornar o valor selecionado no dropdown do estado para o backend, para utilizar como parâmetro da query das cidades, estou utilizando jQuery para isso e me surgiu a dúvida se isso pode ocasionar problemas ao salvar os dados. No forms.py, o ChoiceField de cidades está com o parâmetro "queryset" da seguinte forma : "queryset=Cidade.objects.none()", o que exibe um dropdown vazio, e que vai ser populado com os dados das cidades, utilizando jQuery para inserir esses dados quando o usuário selecionar um estado. O fato de o formulário estar com esse "none()" pode gerar algum problema no cadastro ? Desculpe se for uma dúvida muito específica, vou fazer os testes aqui e acho que consigo verificar isso, mas gostaria de saber o que acha.

regiov commented 1 year ago

Olá @Diogojlq, acho que eu nunca tive que fazer isso antes com Django, mas com certeza é uma situação bem comum que deve ter bastante informação na web (stackoverflow, etc). Acho que o caminho envolve javascript sim, usando onchange no combo do estado e em seguida setando as opções correspondentes no combo de cidade. Imagino que os valores do combo de cidade serão os nomes, certo? É que se for mudar pra uma chave de relacionamento vai ter muita coisa pra mudar no sistema. Melhor continuar armazenando em texto por enquanto.

Diogojlq commented 1 year ago

Sim, inicialmente pensei em criar uma relação entre as cidades e estados, mas vi que seria problemático, então criei duas tabelas, a tabela dos estados tem as colunas pk, nome e sigla, e a tabela de cidades pk, nome e UF. Creio que com apenas uma linha de código, que filtre os estados pelo id que o dropdown retorna, eu consiga pegar a sigla do estado e utilizar para filtrar as cidades que tem essa sigla como UF. Não criei um cache para a call da API, criei o comando que faz uma chamada para a API do IBGE e verifica se tem alguma cidade nova, e utilizei ele para popular as tabelas que mencionei.

regiov commented 1 year ago

Ah, perdão, eu estava me referindo ao impacto de substituir o campo texto da cidade por uma chave de relacionamento nas tabelas voluntario e entidade. Isso teria repercussões em várias partes do sistema. Mas nesse outro caso das tabelas uf e cidade não vejo problema em relacioná-las. Creio que seja até melhor e mais fácil usar.