Modify only one field of the model

I am trying to modify only one field of my modal. For this I have copied the class where I edit the record, but of course, it tells me that there are mandatory fields that I must put.
Is there a way to avoid that and only modify the field that I want?
views.py

class AprobarReclamacion(UpdateView):
    model = Rec
    form_class = RecForm
    template_name = 'reclamaciones/aprobar_reclamacion.html'
    
    def post(self,request,*args,**kwargs):
        request.headers.get('x-requested-with') == 'XMLHttpRequest'
        if request.headers.get('x-requested-with') == 'XMLHttpRequest':
            form = self.form_class(request.POST,instance = self.get_object())
            if form.is_valid():
                nueva_reclamacion = Rec(
                    estado_cod_id = 5,
                )
                form.save()
                mensaje = f'{self.model.__name__} actualizado correctamente!'
                error = 'No hay error!'
                response = JsonResponse({'mensaje': mensaje, 'error': error})
                response.status_code = 201
                return response
            else:
                mensaje = f'{self.model.__name__} no se ha podido actualizar!'
                error = form.errors
                response = JsonResponse({'mensaje': mensaje, 'error': error})
                response.status_code = 400
                return response
        else:
            return redirect('inicio_reclamaciones')

The field I want to modify is estado_cod_id.

How do you want the other fields to appear?

  • Do you even want those other fields to appear?
  • Or do you want them to be shown, but be read-only?

I don’t want them to be displayed since the change of state is done by someone else who simply “authorizes”, that’s why the state changes.

Then I would create a new form (not a model form) with whatever widget you want to use to select the new state, and use the update method on the object to change that one value of that model.

Do you mean create a new form in forms.py?

Yes, along with the appropriate view to handle it.

I get the following:

ValueError: Cannot assign "'5'": "Rec.estado_cod" must be a "Sat_estados" instance.

I need to see all the code related to this - the form and the view.

views.py

class AprobarReclamacion(UpdateView):
    model = Rec
    form_class = RecFormCanvioEstado
    template_name = 'reclamaciones/aprobar_reclamacion.html'
    
    def post(self,request,*args,**kwargs):
        request.headers.get('x-requested-with') == 'XMLHttpRequest'
        if request.headers.get('x-requested-with') == 'XMLHttpRequest':
            form = self.form_class(request.POST,instance = self.get_object())
            if form.is_valid():
                nueva_reclamacion = Rec(
                    estado_cod = 5,
                )
                form.save()
                mensaje = f'{self.model.__name__} actualizado correctamente!'
                error = 'No hay error!'
                response = JsonResponse({'mensaje': mensaje, 'error': error})
                response.status_code = 201
                return response
            else:
                mensaje = f'{self.model.__name__} no se ha podido actualizar!'
                error = form.errors
                response = JsonResponse({'mensaje': mensaje, 'error': error})
                response.status_code = 400
                return response
        else:
            return redirect('inicio_reclamaciones')

forms.py

class RecFormCanvioEstado(forms.ModelForm):
    class Meta:
        model = Rec
        fields = ['estado_cod']

Side note: This following line doesn’t do anything for you and can be removed

Side note: This also doesn’t appear to have any use in this code and can be removed.

Also, from an earlier reply:

[Emphasis added]

You want this to be a regular form with just that one field, not a model form.

Then, when that form is submitted:

I’m a bit lost with “You want this to be a regular form with just that field, not a template form.”
That’s why I asked earlier if I should create another form in forms.py because I wasn’t very clear about what you’re saying about the regular form.

You mean something like this:

class RecFormCanvioEstado(forms.Form):
    estado_cod = forms.TextInput(attrs = {
                    'class': 'form-control',
                    'placeholder': 'Debe aprobar',
                    'readonly':'readonly',
                    })

I’m wondering if we’re dealing with a translation issue.

I did not say “not a template form”, I said to not use a model form. In other words, your form should subclass Form, not ModelForm.

Also, I think your other posts identify that the estado_cod field is a ForeignKey, which means your most appropriate field is going to be a ModelChoiceField.

We may not be understanding each other due to the language change…
I’ll explain a bit what I want to do.
As you comment, I have a ForeignKey field that is estado_cod which puts the value according to another table called sat_estados
What I want is to be able to modify that estado_cod value by clicking on a button so that it goes from one state to another but without having to fill in any form.

On the other hand, I think that the subclass form theme is what I was presenting to you before:

class RecFormCanvioEstado(forms.Form):
    estado_cod = forms.TextInput(attrs = {
                    'class': 'form-control',
                    'placeholder': 'Debe aprobar',
                    'readonly':'readonly',
                    })

Although I don’t know how to apply it to my view class ApprobarReclamacion(UpdateView):
And pass it an Update()
I don’t know if I understood better.
Thank you.

Ok, this is different from everything we’ve talked about before - and in some ways a lot easier.

There are a couple different ways to do this, what I’m outlining below is just one way - and it’s a method we use.

  • Define a view that:

    • Accepts the object’s PK as a URL parameter
    • Updates the estado_cod field with the new value
      (See the docs for update)
    • returns an HttpRedirect to whatever page you want to go to after that field has been updated.
  • Define a url for that view with a url parameter for the pk

On the page where you want this action to be triggered:

  • Define an <a> tag to that new url. You can use a <button type="button"> inside the <a> and </a> tags so that it looks like a button instead of a normal link.

Now, if you choose to continue with using a form:

You wouldn’t. You would be creating a new view to do that. If you want to use a CBV as the base, it would be a FormView for your new form, not an UpdateView.

You don’t “pass it an update”. Your FormView needs to get the object being updated, and you use the update method on that object to change it.

I will go step by step.
First, can I create the view based on a class or does it have to be def?
To update I see that it would be something like this:

Rec.objects.filter(id=pk).update(estado_cod=5)

I’m good?

Either. Functionally, it doesn’t make a difference.

If you create a CBV for this, it would likely use View as the base class. There’s just not a lot of functionality in it.

As a result, if it were me, I’d create this as an FBV.

Correct.

Hello,
I’m starting to get involved and I don’t really know how to continue, I think it’s the least complicated of all but I can’t get out of this.
I have the following:

code views.py

def AprobarReclamacion(pk):
    
    Rec.objects.filter(id=pk).update(estado_cod=5)
    return redirect('inicio_reclamaciones')

urls.py code

path('reclamaciones/aprobar_reclamacion/<int:pk>/', AprobarReclamacion, name='aprobar_reclamacion'),

js code

Here in the js I am not very clear how to indicate the path to the link/button

function listadoReclamaciones(){
    $.ajax({
        url: "/reclamaciones/listado_reclamaciones/",
        type:"get",
        dataType: "json",
        success: function(response){
            if($.fn.DataTable.isDataTable('#tabla_reclamaciones')){
                $('#tabla_reclamaciones').DataTable().destroy();
            }
            $('#tabla_reclamaciones tbody').html("");
            for(let i = 0;i < response.length;i++){
                let fila = '<tr>';
                fila += '<td>' + (i +1) + '</td>';
                fila += '<td>' + response[i]["fields"]['num_reclamacion'] + '</td>';
                fila += '<td>' + response[i]["fields"]['motivo'] + '</td>';
                fila += '<td>' + response[i]["fields"]['fecha_reclamacion'] + '</td>';
                fila += '<td>' + response[i]["fields"]['aprueba'] + '</td>';
                fila += '<td>' + response[i]["fields"]['del_dep_code'] + '</td>';
                fila += '<td>' + response[i]["fields"]['rec.estado_cod.nombre'] + '</td>';
                fila += '<td><button type = "button" class = "btn btn-primary btn-sm tableButton" ';
                fila += 'onclick = "abrir_modal_edicion(\'/reclamaciones/actualizar_reclamacion/' + response[i]['pk']+'/\');"> EDITAR </button>';
                fila += '<a name="" id="" class="btn btn-primary" href="" role="button">APROBAR</a>';
                fila += '</td>';

Here in the js I am not very clear how to indicate the path to the link/button. The last part where it says APROBAR is where I don’t know.

You want to concatenate the desired pk to that url string. How you identify what pk to apply depends upon how you’re constructing the page and the links.

For example, you could define your function with a parameter:
function listadoReclamaciones(pk){
and then you could have:
url: "/reclamaciones/listado_reclamaciones/"+pk+"/",

You could then define your buttons with the onclick attribute to call this function passing the pk for that button as the parameter.

But however you choose to do it, it isn’t something done “automatically” - you need to write the code for this to happen.

The concept is clear on how to do it but the code gets stuck and I don’t know where to go.
I have the def part

def AprobarReclamacion(pk):
    
    reclamacion = Rec.objects.filter(id=pk).update(estado_cod=5)
    return redirect('inicio_reclamaciones')

I don’t know if that is enough… on the urls side I have this

    path('reclamaciones/aprobar_reclamacion/<int:pk>/', AprobarReclamacion, name='aprobar_reclamacion'),

And I would be missing the theme of the button. Of course, I show the records with a DataTable as I already commented, so I need to add that button/link inside the js function (part that I don’t know how to do)