domingo, 29 de septiembre de 2013

jQuery Autocomplete en Django

Hola todos, esta vez vamos hacer algo muy útil cuando tenemos un campo estilo ForeignKey y se nos hace muy grande cuando tenemos muchos datos, como sabemos un campo ForeignKey nos hace un campo select en el formulario.

Tenemos el siguiente modelo:
class Persona(models.Model):
    cedula = models.CharField(unique=True, max_length=10)
    nombres = models.CharField(verbose_name='Nombres', max_length=60)
    apellidos = models.CharField(verbose_name='Apellidos', max_length=60)
class Proyecto(models.Model):
     titulo = models.CharField(max_length=200)
     autor = models.ForeignKey(Persona)
Ahora vamos a crear el forms.py, donde vamos a crear un campo adicional, que vamos a llamar persona_display:
class ProyectoForm(forms.ModelForm):
     persona_display = forms.CharField(max_length=100, help_text='tipee Cedula, Nombre o Apellido') 
     class_Meta:
          model = Proyecto
          fields=('titulo', 'persona_display', 'autor',) 
     def __init__(self, *args, **kwargs):
          super(ProyectoForm, self).__init__(*args, **kwargs)
          self.field['persona_display'].label = "Agrege el Autor"
          self.fields['autor'].widget = forms.HiddenInput()
¿Qué hemos hecho hasta aquí? 

Primero creamos nuestro formulario donde agregamos un campo adicional llamado persona_display, en el constructor de la clase hemos dado algunas características al campo persona lo hemos ocultado y le hemos agregado una etiqueta al nuevo campo persona_display

Ahora creamos nuestra url en urls.py:
url(r'^persona/autocomplete/$', 'persona_auto_complete', name='persona_auto_complete'),
Ahora la vista en views.py:
 def persona_auto_complete(request):
q = request.REQUEST['term']
if q:
qset = (
Q(cedula__istartswith=q) |
Q(nombres__icontains=q) |
Q(apellidos__icontains=q)
)
personas = Persona.objects.filter(qset).distinct()
else:
personas = []
personas_list = []
for p in personas:
value = '%s, (%s, %s)' % (p.cedula, p.nombres, p.apellidos)
p_dict = {'id': p.id, 'label': value, 'value': value}
personas_list.append(p_dict)
return HttpResponse(simplejson.dumps(personas_list))
Ahora podemos probar lo que hemos hecho, escribiendo en nuestro navegador:
http://localhost:8000/persona/autocomplete/?term=an
En este caso estamos buscando las personas que contengan en el nombre o apellido las letras "an" y nos mostrara un resultado como este:

[{"id": 3, "value": "1234567, (Ana Cecilia, La Cruz)", "label": "1234567, (Ana Cecilia, La Cruz)"}]

Si tenemos este resultado, ya podemos ahora agregar el código JQuery del plugin AutoComplete en nuestro template:

Recuerde que debe agregar los css del Jquery:
<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css">
el formulario:
<form action="" method="post">{% csrf_token %}
<div class="forms">
    {{ form }}
    <input type="submit" name="submit" value="Salvar" />
</div>
</form>
Y ahora el JQuery y JQuery UI con el script de que hace accionar nuestro autocomplete:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js" type="text/javascript"></script>
<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
<script>
       $( document ).ready( function() {
        $("#id_persona_display").autocomplete({
        source: "{%  url 'persona_auto_complete' %}",
        dataType: "jsonp",
        selectFirst: true,
        minLength: 2,
        select: function(event,ui) {
        $("#id_autor").val(ui.item.id)
        }
        });
       });
</script>
Explicando un poco, estamos activando el auto complete en el campo que creamos en el form.py llamado persona_display, llamamos la url del autocomplete en la vista y le decimos por el parámetro minLength que empiece a buscar a partir del segundo carácter y al escoger le agregamos el id al campo autor, para que no nos de error, ya que es un campo requerido por ser clave.

Este es un ejemplo de como nos quedara el autocomplete,


Y eso es todo, espero que les sirva y lo pongan en practica en sus proyectos. Espero sus comentarios. Hasta la próxima.

No hay comentarios:

Publicar un comentario