JCeb's Blog

Programación, investigación, proyectos, vida y mas…

Django con Jquery form y un image field latoso

with 3 comments

Ahora que andamos desarrollando la nueva versión de pikhub, andamos procurando un codigo hermoso, por lo que agregamos a nuestros javascripts uno llamado jquery.form, el plugin está bien chingon, te permite hacer peticiones por ajax sin necesidad de definir los parametros que solicita jquery y la petición por ajax la puedes armar a apartir de tu form.

Por ejemplo:

#!html
<form id="profile_form" class="ajax" 
action="/settings/profile/" method="post" 
enctype="multipart/form-data">
    {%csrf_token%}
    {{user_form.as_table}}
    {{profile_form.as_table}}
    <input type="submit" value="{%trans 'Enviar'%}" />
</form>

#!javascript
$('form.ajax').submit(function(){
        $(this).ajaxSubmit({
            dataType:  'json',
            success:  function(json){
                alert(json.message);
            }
        });
        return false;
    });

Y el codigo es generico pero hay un pequeño detalle, si dentro de los campos del formulario hay un imagefield y si tienes una versión del jquery.form del 2009 o 2010, la cosa no funcionará correctamente. Pero si en cambio tienes la versión 2011, todo funciona perfectamente, pero te diré que no es tan facil como parece, seguramente pensaras ah pues como es una petición por ajax, solo bastara con que en mi vista(views.py) haga esto:

@login_required
def profile(request):
    user = User.objects.get(username=request.user.username)
    profile = user.get_profile()
    profile_form = ProfileForm(instance=profile)
    alert = _(u'Datos guardados').encode('utf-8')
    user_form = UserForm(instance=user)
    if request.POST:
        user_form = UserForm(request.POST, instance=user)
        profile_form = ProfileForm(request.POST, request.FILES, instance=profile)
        if user_form.is_valid() and profile_form.is_valid():
            user_form.save()
            profile_form.save()
        else:
            alert = _(u'Datos incorrectos, intenta de nuevo').encode('utf-8')
    if request.is_ajax():
        json_obj = {'message' : alert, 'avatar':user.get_profile().avatar.url}
        return HttpResponse(json.dumps(json_obj))
    args = {
        'profile_form':profile_form,
        'user_form':user_form
    }
    return render('settings_profile.html', args, context_instance=rc(request))

El código permite que el formulario responda a HttpRequest y a XMLHttpRequest o ActiveXObject, gracias a la función is_ajax().

Pero permiteme desilusionarte, si esperas que al guardar tu formulario con una imagen en él, te va a responder satisfactoriamente, te sentaras a esperar porque jamas te responderá jeje. Esto debido a que jquery.form manda la imagen por medio de un iframe invisible para nosotros, un trucaso, pero hay que saber como tratarlo, por lo tanto, si deseamos que todo funcione bien, habrá que agregar un campo como comodin a nuestro formulario, en mi caso lo agregue con javascript, usando j2h.js(https://bitbucket.org/julianceballos/j2h/src/9c468b91cec7/j2h.min.js), de la siguiente forma:

$('#profile_form').append($.j2h('input',{
        'type':'hidden',
        'name':'xhr',
}));
$('#profile_form').submit(function(){
        $(this).ajaxSubmit({
            dataType:  'json',
            success:  function(json){
                alert(json.message);
            }
        });
        return false;
});

Así si el javascript está activado el formulario se irá con un campo de más oculto que se llama xhr.
Luego en la vista(views.py) solo habrá que revisar que ese campo existe y si existe quiere decir que estamos enviando por ajax los datos y jquery.form está haciendo sus trucos para subir la imagen sin recargar la página. Por lo que la vista queda:

@login_required
def profile(request):
    user = User.objects.get(username=request.user.username)
    profile = user.get_profile()
    profile_form = ProfileForm(instance=profile)
    alert = _(u'Datos guardados').encode('utf-8')
    user_form = UserForm(instance=user)
    if request.POST:
        user_form = UserForm(request.POST, instance=user)
        profile_form = ProfileForm(request.POST, request.FILES, instance=profile)
        if user_form.is_valid() and profile_form.is_valid():
            user_form.save()
            profile_form.save()
        else:
            alert = _(u'Datos incorrectos, intenta de nuevo').encode('utf-8')
    if request.POST.__contains__('xhr'):
        json_obj = {'message' : alert, 'avatar':user.get_profile().avatar.url}
        return HttpResponse(json.dumps(json_obj))
    args = {
        'profile_form':profile_form,
        'user_form':user_form
    }
    return render('settings_profile.html', args, context_instance=rc(request))

Y listo ahora todo debe funcionar perfectamente.

Written by JCeb

19 mayo, 2011 a 6:04 pm

Publicado en Uncategorized

3 comentarios

Subscribe to comments with RSS.

  1. if request.POST.__contains__(‘xhr’):

    cambia por:

    if request.POST.get(“xhr”, False):

    mas bonito y en tu formulario >> action=”/settings/profile/” usa {% url %} para no hacer DRY

    j2h.js ? reinventaste

    $(““, {href:’http://www.google.com’, text:”google”}).appendTo($(“body”));

    zoman

    24 mayo, 2011 at 6:39 pm

  2. jQuery( html, [ ownerDocument ] )

    zoman

    24 mayo, 2011 at 6:42 pm


Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: