'initial value of field modelform_factory in Django

This is my first post on StackOverflow. I'm also new to using Django (I'm actually using version 3.2). I have read about how to set the initial value of a field in a form using the initial parameter of a modelform_factory. I have followed several code examples but, the field does not display the value. My App uses the crispy_form plugin.

The matricula field in my model is the one I want to set up with a value that is taken from a query getting the total number of records in the teacher table plus 1.

When I load the page, the matricula field in the form does not display the desired value. what am I doing wrong?

Thanks for your help.

Sorry for my English. It is not very good. I hope you can understand me.

This is my code:

Model:

class docente(models.Model):

    matricula = models.CharField(max_length=10, verbose_name="Matrícula", unique=True)

    nombre = models.CharField(max_length=80)
    apellidoPaterno = models.CharField(max_length=80, verbose_name=" Apellido Paterno")
    apellidoMaterno = models.CharField(max_length=80, verbose_name="Apellido Materno", blank=True) # Campo opcional

    direccion = models.CharField(max_length=150, verbose_name="Dirección", blank=True)             # Campo opcional
    telefono = models.CharField(max_length=13, verbose_name="Teléfono", blank=True)                # Campo opcional
    email = models.EmailField(verbose_name="Correo Electrónico", blank=True)                       # Campo opcional
    colonia = models.CharField(max_length=150, blank=True)         # Campo opcional
    comunidad = models.CharField(max_length=150, blank=True)       # Campo opcional
    fecha_nacimiento = models.DateField(verbose_name="Fecha de Nacimiento", blank=True, null=True) # Campo opcional 
    estado_civil = models.ForeignKey(estado_civil, verbose_name="Estado Civil", on_delete=models.CASCADE)
    profesion_ocupacion = models.CharField(verbose_name="Profesión/Ocupación", max_length=150, blank=True, null=True) # Campo opcional
    ultimo_grado_estudios = models.ForeignKey(grado_estudios, verbose_name="Último Grado de Estudios", on_delete=models.CASCADE)
    otros_estudios = models.ManyToManyField(otros_estudios, verbose_name="Otros estudios")

    def __str__(self):
        return self.nombre

Form:

class FormularioDocente(forms.ModelForm):
   
    class Meta:
        model = docente
        fields = '__all__' 
        widgets = {
            'matricula': TextInput(attrs={'readonly': 'readonly'})
        }

View:

def nuevo_docente(request):
    mensaje = "Nuevo Docente"

    cuantos = docente.objects.count()
    cuantos+=1

    initial_data = {'matricula':cuantos}

    formFormulario = modelform_factory(docente, form=FormularioDocente)
    form = formFormulario(request.POST, initial=initial_data)

    if request.method=='POST':
        if form.is_valid():
            form.save()
            messages.success(request, MENSAJE_SUCCESS_FORMULARIO)
            form = formFormulario() # Limpiar el formulario ya procesado y guardado
        else:
            messages.error(request, MENSAJE_ERROR_FORMULARIO)
            messages.error(request, form.errors)

    return render(request, 'escuela/nuevo_form.html', {'mensaje': mensaje, 'form':form}) 

Template:

{% extends 'escuela/base.html' %}
{%load crispy_forms_tags%}

{% block content %}    

    <div class="col-md-8 offset-md-2 ">
        <h2>{{mensaje}}</h2>
    </div>

    <div class="main"> 

        {% include 'escuela/messages.html' %}
        
        <form method="POST" class="post-form">
            {% csrf_token %}
            <table class="table table-borderless table-responsive">
                {{form|crispy}}
            </table>    
            <br>
            <button type="submit" id="boton-formulario" class="save btn btn-primary">Guardar</button>  
        </form>
    
    </div>

{% endblock %}


Solution 1:[1]

When you pass request.POST to your form class, you're actually saying data=request.POST, which is overriding your initial values. This is because if you are not submitting a form then request.POST equals an empty dictionary, and data (even an empty dictionary of data) is used over initial values.

To counteract this, try:

form = formFormulario(request.POST or None, initial=initial_data)

An empty dictionary has a Falsey value, so here you are saying if request.POST is falsey, then data=None. In the absence of a dictionary, your initial values should be used instead.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 SamSparx