[Answer]-Add values to empty ModelForm

1👍

I’m still not exactly sure what you’re asking but let’s clean this up a bit.

First off, you need to be leveraging the built-in UserCreationForm from django.contrib.auth.forms. Second, never, ever use the data directly from the form post to hydrate a model object as this completely bypasses any cleaning of data performed by the form classes. Third, the view can be greatly simplified. I’m going to assume you’re using Django 1.7:

# forms.py

from django import forms

from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User

from .models import Perfil

class UsarioForm(UserCreationForm):
    class Meta:
        model = User
        exclude = ()

class PerfilForm(forms.ModelForm):
    class Meta:
        model = Perfil
        exclude = ('usario',)


# views.py

from django.shortcuts import render

from .forms import UsarioForm, PerfilForm

def nuevo_usario(request):
    usario_form = UsarioForm(request.POST or None)
    perfil_form = PerfilForm(request.POST or None)

    if request.method == 'POST':
        if usario_form.is_valid() and perfil_form.is_valid():
            usario = usario_form.save()
            perfil = perfil_form.save(commit=False)
            perfil.usario = usario
            perfil.save()
            perfil.save_m2m()

    return render(request, 'nuevousario.html',
        {'usario_form': usario_form, 'perfil_form': perfil_form})

Let the ModelForm classes do what they are designed to do – create objects from sanitized data. You don’t have to do all of that work by hand in the view. You template code also needs some help:

# nuevousario.html

<form action="." method="post" enctype="application/x-www-form-urlencoded">
    <table>
        <tfoot>
            <tr>
                <td>
                    {% csrf_token %}
                    <button type="submit">Registrar</button>
                </td>
            </tr>
        </tfoot>
        <tbody>
            {{ usario_form.as_table }}
            {{ perfil_form.as_table }}
        </tbody>
    </table>
</form>

Are you sure you want to use a table for this form? Is it really tabular data? Doesn’t seem very semantically correct. You might consider using an ordered list: <ol>

Hope that helps you out.

0👍

Taking the comments of @Brandon i have changed my code like this.

I added two URLs, one for the empty form and the other to GET the user data

#urls.py

url(r'^usuarios/$','main.views.usuarios',name='usuarios'),
url(r'^usuarios/(\d+)$','main.views.usuarios',name='editar_usuario'),

In only one view that can handle both URLs, I look for a user_id, if there is Nothing, then I display the empty form, otherwise I get the user and profile data, and with an instance I put the data into the input fields

#views.py

def usuarios(request,id_usuario=None):
    usuarios = User.objects.all()
    #Pide información de un usuario - Ask for user Info
    if id_usuario is not None: 
        usr = User.objects.get(pk=id_usuario)
        prf = Perfil.objects.get(usuario=usr)
        usuario_form = UsuarioForm(instance=usr)
        perfil_form = PerfilForm(instance=prf)
    #El formulario está vacío para nuevo usuario -Empty User Form
    else:
        usuario_form = UsuarioForm(request.POST or None)
        perfil_form = PerfilForm(request.POST or None)
    #Botón Registrar - Register Button pressed
    if request.method == 'POST':
        #Si está editando se obtiene la instancia del que quiere guardar - If edit, then gets the instance to save
        if id_usuario is not None:
            usuario_form = UsuarioForm(request.POST, instance=usr)
            perfil_form = PerfilForm(request.POST, instance=prf)
        #Finalmente guarda - Finally Saves the form
        if usuario_form.is_valid() and perfil_form.is_valid():
            usuario = usuario_form.save()
            perfil = perfil_form.save(commit=False)
            perfil.usuario = usuario
            perfil.save()
            HttpResponseRedirect('/usuarios/')
    return render(request,'usuarios.html',locals())

Finally I added some bootstrap/crispy into the form and make it looks better.

#Template usuarios.html
{% block content %}
<div class="row">
    <div class="col-md-4">
        <h3>Usuarios Registrados</h3>
        <ul>
        {% for usuario in usuarios %}
            <li><a class="usuario_link" href="/usuarios/{{usuario.pk}}">{{ usuario.username }} - {{ usuario.first_name }}</a></li>
        {% empty %}
            <li>No hay usuarios.</li>
        {% endfor %}
        </ul>
    </div>
    <div class="col-md-5">
        <fieldset>
            <form id="form" method="post" action=''>{% csrf_token %}
                {{usuario_form|crispy}}
                {{perfil_form|crispy}}
                <p><input class="btn btn-default" type="submit" value="Registrar"/></p>
            </form>
        </fieldset>
    </div>
    <div class="col-md-2 col-md-offset-1">
        <a href="/usuarionuevo/"><input class="btn btn-default" type="button" value="Nuevo Usuario" /></a>    
    </div>
</div>
{% endblock %}

I hope it helps someone, I am new in python and django so, thanks again @Brandon for the fantastic counseling.

If anyone have a better answer, let me know please.

Leave a comment