regiov / voluntarios

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

Incluir novo modo de visualização de busca de voluntários, permitindo acessar diretamente a página de detalhe dos voluntários #74

Open regiov opened 6 months ago

regiov commented 6 months ago

Sugestão: incluir ao final dos campos de busca de voluntários, logo após "Ordenado por: () Nome () Área de Trabalho", uma nova opção: "Modo de visualização: () paginação () sequencial". O modo de paginação é o que funciona atualmente. O modo sequencial, quando ativado, irá exibir diretamente a página de detalhe do primeiro voluntário retornado na busca, e essa página deverá exibir os botões "anterior" (quando houver) e "próximo" (quando houver) para navegação entre os resultados. Caso a busca não retorne ninguém, pode-se exibir a página do modo de paginação.

Diogojlq commented 6 months ago

@regiov, acredito que se colocarmos como "paginação" e "sequencial" não ficará claro a função dos modos de visualização, talvez algo como "visualização detalhada" ou algo que sugira que os resultados serão mostrados um a um.

regiov commented 6 months ago

@Diogojlq não sei se vamos conseguir encontrar palavras que consigam traduzir bem essa funcionalidade. Talvez seja o caso de incluir um ícone de ajuda com tooltip explicando melhor. De qualquer forma, é fácil alterar o nome depois. E também os usuários podem facilmente clicar em cada opção e simplesmente descobrir o que cada uma faz.

Diogojlq commented 6 months ago

Boa noite @regiov, coloquei os botões de navegação logo abaixo do nome do voluntário, porém, como está, eles irão aparecer sempre, não só quando estiver sendo feita a busca no modo de visualização sequencial, isso é um problema ? Estou fazendo da seguinte forma:

     `else: # Sequencial
        if voluntarios:  # Certifica que a lista não está vazia
            voluntario = voluntarios[0]
            proximo_voluntario = Voluntario.objects.filter(pk__gt=voluntario.pk).order_by('pk').first()
            voluntario_anterior = Voluntario.objects.filter(pk__lt=voluntario.pk).order_by('-pk').first()

            context = {'voluntario': voluntario,
                       'voluntario_anterior': voluntario_anterior.pk if voluntario_anterior else None,
                       'proximo_voluntario': proximo_voluntario.pk if proximo_voluntario else None}

            template = loader.get_template('vol/exibe_voluntario.html')

            return redirect('exibe_voluntario', voluntario.pk, voluntario_anterior.pk, proximo_voluntario.pk)`

Seria "correto" incluir os parâmetros "voluntario_anterior" e "próximo_voluntario" na view "exibe_voluntario"? Tentei criar um context e utilizar o HttpResponse, mas dessa forma não consigo passar o voluntário anterior e o próximo para a view "exibe_voluntario", então a navegação só funciona no primeiro clique, pois a view não estava recebendo os parâmetros.

Obs: Sei que está cheio de erros bobos, mas queria te atualizar

regiov commented 6 months ago

@Diogojlq, não ligo pra erros "bobos". O mais importante é ver que a pessoa está se dedicando, se esforçando, não tem medo de se expor, de interagir e tem disposição para ouvir e aprender. Acredite, isso é o mais importante e o mais difícil de conquistar.

Quanto aos botões, sim, só faz sentido exibir em modo sequencial. Lembre que existem outras situações que a gente pode chamar a página de voluntário - por exemplo na lista de voluntários inscritos para uma vaga - que não tem sequer uma busca prévia por trás.

Mas isso é algo fácil de resolver: acho que basta alterar o template de exibição do voluntário e colocar um "if parâmetro modo sequencial ativado", daí exibe os botões. A view de exibição do voluntário penso que poderia se manter totalmente inalterada. Só mexer no template mesmo.

Outro detalhe é que o clique nos botões próximo/anterior talvez devesse chamar uma outra view que faria o controle da paginação um a um. Sugestão de url: voluntario/busca/sequencial. Sugestão de view: busca_sequencial_voluntarios. Só que pra funcionar, essa view precisará dos parâmetros de busca, que você deverá passar no clique dos botões. Pode até usar um form com método GET, colocando os parâmetros e seus valores em campos "hidden". A lógica dessa view será praticamente a mesma da busca (mesmo código da view busca_voluntarios ao montar os filtros), ou seja, montando a query com base nos parâmetros, só que você não precisará necessariamente do objeto paginador, podendo fazer você mesmo a paginação um a um utilizando um parâmetro para indicar em que ponto está na sequência e colocando o valor parâmetro no final do queryset sob a forma de array slice: myquery.[pos:pos+1]. Daí essa view pode no fim chamar a view de exibir o voluntário da mesma forma que você fez no código de exemplo.

Muita coisa estou falando de cabeça, talvez tenha algum erro ou imprecisão no que eu falei, ou algum jeito melhor de implementar. Fique à vontade pra interagir...

Diogojlq commented 6 months ago

@regiov o código dentro do else para modo de visualização sequencial da view 'busca_voluntarios' está assim:

       `else: # Sequencial
        if voluntarios:
            voluntario = voluntarios[0]
            context = {'voluntario': voluntario,
                       'voluntarios': voluntarios,
                       'modo_visualizacao': modo_visualizacao}
            template = loader.get_template('vol/exibe_voluntario.html')
            return HttpResponse(template.render(context, request))`

Será que não é possível passar a lista de voluntários, já filtrada pelos parâmetros de busca, diretamente para a view nova(busca_sequencial_voluntarios)? Assim apenas precisaria configurar a paginação um a um ao clicar nos botões, partindo do primeiro voluntário da lista, que já estará sendo exibido. Foi pensando nisso que abarquei 'voluntarios' no context.

Outra coisa, ao exibir o primeiro voluntário da forma que está, os botões ficam 'disabled' por não estar recebendo 'proximo_voluntario' e 'voluntario_anterior', devo enviar esses parâmetros direto da view 'busca_voluntarios' até o primeiro clique que começará usar a view nova ?

regiov commented 6 months ago

@Diogojlq em linhas gerais esse código em busca_voluntarios está correto, sim. Inclusive talvez nem seja necessário criar outra view como sugeri anteriormente. Podemos tentar implementar apenas com o busca_voluntarios e o exibe_voluntario. Veja se faz sentido pra vc:

Talvez funcione assim...

Diogojlq commented 6 months ago

@regiov no context contido no código do meu último comentário, 'voluntarios' já contém uma lista já filtrada pelos parâmetros de busca, não seria mais eficiente passar essa lista diretamente para a view exibe_voluntario ? Imagino que dessa forma seria necessário apenas iterar por essa lista sem precisar passar os parâmetros de busca para a view.

E também não ficou muito claro o que exatamente deve ser atribuído em "seq", e como substituir o 0 por "seq" e ainda assim indicar o primeiro da lista,

regiov commented 6 months ago

@Diogojlq antes de pensar em eficiência penso mais em tentar separar bem o que cada parte do sistema faz (o que nem sempre é muito fácil), ou seja, deixar que exibe_voluntario se concentre na tarefa de apenas exibir o voluntário, e que busca_voluntario se concentre na tarefa de buscar voluntários - incluindo aí a iteração. Existem alguns detalhes sutis nisso tudo. Por exemplo, no código original que você compartilhou, o busca_voluntarios faz uso direto do template exibe_voluntario.html. Sempre que precisarmos exibir um voluntário, acho melhor chamar a função exibe_voluntario, pois pode ser que exista (ou venha a existir) alguma coisa a mais a ser feita e que pode ficar lá na função (exemplo: contabilizar alguma estatística, fazer alguma verificação de permissão, etc). Melhor deixar tudo isso encapsulado num só lugar. Inclusive se algum dia quisermos trocar o nome do template, é só trocar naquele único lugar.

A ideia desse parâmetro (seq) é indicar em que ponto estamos na iteração: 0, 1, 2, 3, 4... e de quebra indicar que estamos em modo de busca sequencial (se seq for nulo, não estamos em busca sequencial). Pensando bem, talvez seja necessário mais um parâmetro, pois ao exibir um voluntário vamos precisar saber:

Nesse último caso acho que valeria a pena também especificar o tamanho da lista com outro parâmetro adicional. Algo do tipo:

def exibe_voluntario(request, id_voluntario, modo_seq_posicao_atual=None, modo_seq_tamanho_lista=None):

Acho que aí sim teríamos tudo: exibe_voluntario já recebe o request, que tem todos os parâmetros da busca, já recebe o id do voluntário a ser exibido, e agora passaria a receber esses outros dois parâmetros para controlar a exibição dos botões. Daria inclusive pra exibir algo do tipo: registro 5 de 30 [anterior] [próximo].

Mas se quiser tentar de outro jeito, não tem problema. Sempre tem várias formas de fazer a mesma coisa. Só não vejo muito como fugir de propagar os parâmetros GET da busca entre as requisições, para a partir deles montar os filtros, reconstruir a query voluntarios e fazer as próximas iterações.

Diogojlq commented 5 months ago

Boa noite @regiov, estou tentando usar as sessions do Django para passar a lista entre views, da seguinte forma:

     `else: # Sequencial
        if voluntarios:
            id_voluntario = str(voluntarios[0].pk)
            lista_voluntarios = list(voluntarios.values())
            voluntarios_json = json.dumps(lista_voluntarios, cls=DjangoJSONEncoder)
            request.session['voluntarios'] = voluntarios_json
            modo_seq_posicao_atual = 1
            modo_seq_tamanho_lista = len(voluntarios)
            return exibe_voluntario(request,id_voluntario, modo_seq_posicao_atual, modo_seq_tamanho_lista)`

Gostaria de saber: há algum problema nessa abordagem?

regiov commented 5 months ago

Fala @Diogojlq! Bom, é possível fazer isso, mas não vejo necessidade. As desvantagens são que esse mecanismo se não me engano depende de cookie (mesmo que já estejamos usando), mas a principal é que a lista pode ser bastante grande, pois hoje temos praticamente 100 mil voluntários cadastrados. Se a busca não tiver nenhum filtro, o resultado será essa quantidade de registros...

Diogojlq commented 5 months ago

Entendo, você tem alguma sugestão de como reconstruir a query na view exibe_voluntario ? Creio que eu possa, se for um bom caminho, passar os parâmetros através das sessions, invés de passar a lista de voluntários...

regiov commented 5 months ago

Se eu fosse você, ficaria apenas repassando os parâmetros de busca através do html. Basta que os botões "próximo" e "anterior" fiquem dentro de um

e nesse form você coloque inputs escondidos (). Ao fazer isso, a view de busca já vai receber os parâmetros da busca e montar a query de acordo. Qualquer coisa me avise...

regiov commented 5 months ago

Nossa, perdão, o github escondeu minhas tags de exemplo! Peraí...

regiov commented 5 months ago

<form method="GET" action="{% url 'busca_voluntarios' %}"> <input type="hidden" name="nome_do_parametro" value="valor_do_parametro/>"

regiov commented 5 months ago

Ou seja, faça com que os botões "próximo" e "anterior" sejam <input type="submit"/> dentro desse form, e coloque quantos inputs hidden forem necessários pra repassar todos os parâmetros de busca. O nome dos parâmetros você vê no código do busca_voluntarios, e o valor deles no template é só pegar do request.GET.nome_parametro. Estou falando sem ver o código, então pode ser que tenha algum ajuste nisso tudo...

Diogojlq commented 5 months ago

Não seria possível recuperar os parâmetros da busca e montar uma query novamente dentro de exibe_voluntario, criando uma lista e iterando por ela ?

regiov commented 5 months ago

Sim, é possível, mas aí entra só aquela questão filosófica de tentar separar o que cada função faz: busca_voluntarios monta as queries de busca e chama o output apropriado (se for modo paginação exibe a página de resultados, se for modo sequencial chama o exibe voluntario), enquanto o exibe_voluntario se concentra apenas em exibir o voluntário. Você até pode incluir essa lógica de montar a query no exibe_voluntario, mas o busca_voluntarios já tem esse código pronto,

regiov commented 1 month ago

Olá @Diogojlq, pensei algumas coisas sobre essa issue que mudam um pouco a especificação original. Queria ver o que você acha. É que talvez não seja necessário criar uma nova opção na busca (modo sequencial/lista), pois quanto mais pudermos simplificar para o usuário melhor. Pensei o seguinte: a página de detalhes do voluntário pode ser acessada tanto através do clique na paginação de resultados de busca quanto de forma independente (ex: clicando no nome de um voluntário inscrito numa vaga). O que precisamos é distinguir entre essas duas situações. Quando se acessa a página a partir da lista, podemos passar um parâmetro que seria a posição do voluntário na lista. Tendo esse parâmetro, podemos sempre exibir os botões próximo/anterior (quando tiver próximo e anterior). Ou seja, ao fazer uma busca de voluntários, sempre vamos exibir a lista. mas se clicarmos em algum voluntário na lista, teremos os botões de navegação aparecendo lá. Ao passo que se a página do voluntário for acessada por outros meios sem ser do resultado de uma busca, aí não se deve exibir os botões. Faz sentido pra você também?

Diogojlq commented 1 month ago

Fala @regiov, desculpa a demora. Pra mim faz todo sentido, vou começar implementar dessa forma.

Diogojlq commented 2 weeks ago

Olá @regiov, tenho duas perguntas. Primeira: qual seria melhor forma de indexar o perfil de um voluntário na lista? Pensei em passar a lista como um todo, mas acho que a carga de dados vai ficar muito volumosa, então pensei em passar os parâmetros e refazer a query dentro da view de exibição do voluntário, e aí vêm a outra dúvida: qual a melhor forma de manter a localização do voluntário que foi clicado? Estou enferrujado...

regiov commented 2 weeks ago

Fala @Diogojlq, deixa eu também relembrar aqui... Bom, na view que faz a busca de voluntários tem um parâmetro chamado "voluntarios" que na verdade é a página atual do paginador a ser exibida. Isso significa que dentro do template você consegue usar voluntarios.start_index pra saber o índice sequencial (iniciando em 1) do primeiro voluntário daquela página. Ou seja, se você somar isso com a variável forloop.counter0, em cada loop você obtém a posição daquele voluntário na busca e consegue passar isso como parâmetro. Exemplo: url_exibe_voluntario?seq={{ voluntarios.start_index|add:forloop.counter0 }}

Não testei, mas acho que é isso que eu tentaria.

regiov commented 2 weeks ago

Só que além desse parâmetro seq, você precisaria repassar todos os parâmetros da busca em todos os links na página de resultados da busca de voluntários (ex: url_exibe_voluntario?seq=55&param_busca1=val1&param_busca2=val2...), de forma que o exibe_voluntario possa utilizar esses parâmetros nos botões anterior/próximo, que usariam seq-1 e seq+1 respectivamente, chamando a busca com os mesmos parâmetros de busca.

regiov commented 2 weeks ago

Por fim, a lógica da busca precisaria prever a possibilidade de receber o parâmetro seq. Quando esse parâmetro existir, não é necessário construir o paginador. Bastaria montar toda a busca e retornar o exibe_voluntario passando como parâmetro o id do voluntário na posição "seq" do queryset voluntarios. Acho que é mais ou menos isso que eu faria!

Diogojlq commented 2 weeks ago

Olá @regiov, obtive algum progresso, finalmente, parece até que estou reaprendendo a programar. No momento estou conseguindo navegar entre os perfis de voluntários, porém por algum motivo que ainda não descobri, eles só ficam funcionais depois que clico a primeira vez, sendo que no primeiro clique ele apenas recarrega a página no mesmo voluntário, deve ser algum erro na passagem de parâmetros entre as páginas.

Também estou pensando que seria interessante, além dos botões de navegação, adicionar um botão "retornar à busca", o que acha?

regiov commented 2 weeks ago

Legal, @Diogojlq. Talvez seja alguma diferença nos índices. O parâmetro provavelmente percorre os registros iniciando em 1, mas o queryset inicia com índice zero. Talvez seja algo do tipo. Acho boa a ideia do botão pra ver os resultados de novo. Bem pensado!