Home > Blockchain >  How to dinamically access to a field in django form to change instance
How to dinamically access to a field in django form to change instance

Time:09-12

Using a generic CreateView in Django I'm trying to save only the fields that have been changed by user.

I'm trying to do this in my view:

def form_valid(self, form):
        if form.has_changed():
          
          for field in form:
           

            if field.name in form.changed_data:
            
                continue
                
            else:
               
                form.instance.field=None

In the last line I got this error:

object has no attribute 'field'

Is there a way to dynamically access to each field in the form? so I could change it?

CodePudding user response:

Is there a way to dynamically access to each field in the form. Yes.

form.fields[field_name]

So I could change it? Yes.

form.fields[field_name] = django.forms.Charfield(required=False)

But in your code, probably you want to achieve value of the field:

field_value = form[field_name].value

If you have a data bounded field, you can change also data of form:

form.data(form.add_prefix(field_name)) = new_value 

But this is already wrong approach to change something here.

I can imagine: in your case you don't understand how form / modelform saves the data and therefore you want to do something unnecessary:

Once more time, how ModelForm "saves" the data in DB:

  1. Form validate the data.
  2. Form clean the data.
  3. on form.save(**kwargs) - Form create the instance and:
  • call instance.save() if form.save(commit=True)
  • dont call instance.save() if form.save(commit=False)
  1. Instance saves the data.

Form don't save anything itself, instance.save - There is all what you need.

instance.save(self, force_insert=False, force_update=False, using=None, update_fields=None)

In your case you use CreateView - there all fields should be initiated, you can not UPDATE something, this something not exists yet. You can only avoid empty values, if you want.

def form_valid(self, form): if form.has_changed(): form.changed_data = {key:val for key,val in form.changed_data.items() if val} return super().form_valid(form)

al last: form.instance.field is ridiculous

  • form has fields. You can achieve every field by name.
  • Model class has fields. You can achieve every field by name.
  • instance has attributes or properties. You can achieve every attribute by name.

And right now: what you are really want to do?

CodePudding user response:

What I'm trying to do is to update objects in a Model, but not directly in one step. What I need is that when a user wants to update an object, he can suggest some changes but before updating the object other user should approve his suggestions before saving changes.

As the model has many fields and changes could affect only come fields I want to modify only the edited fields.

I guess this is not the best approach, but this is what I did:

I created a second model to save change suggestions, so I have two models looking almost the same:

class MainModel(models.Model):
    name= models.CharField(max_length=100)
    field_1= models.CharField(null=True,blank=True, max_length=200)
    field_2= models.CharField(max_length=100)
    field_3= models.CharField(max_length=100)
    ...
    field_n = bla bla bla

class SuggestionsModel(models.Model):
    
    name= models.Foreingkey(MainModel, on_delete=models.CASCADE)
    field_1= models.CharField(null=True,blank=True, max_length=200)
    field_2= models.CharField(null=True,blank=True, max_length=200)
    field_3= models.CharField(null=True,blank=True, max_length=200)
    ...
    field_n = bla bla bla

    suggested_by = models.Foreingkey(User, on_delete=models.CASCADE)
    approved= models.BooleanField(default=False)
    checked= models.BooleanField(default=False)

and in views what I did is get the 'approved' field in the form, if the user selected "True" I access every field in MainModel and check if the suggestion contains any changes, if it does, I change it in MainModel. Finally I Update the SuggestionsModel.

I'm still working on it. What I have at the moment is something like this in the UpdateView:

def form_valid(self,form):
    
    clean=form.clean()
    
    object_to_update=clean.get('name')
    approved= clean.get('approved')
    
    if approved==False:

        #I update the suggestion as checked and that's it.


     else:

        #the suggestion was approved, so changes should be updated in MainModel:

    fields=MainModel._meta.fields #I get a list of fields in MainModel

    for field in fields:
        
        changed = clean.get(field.name) # I check if the field named campo.name has being changed or not
        
                   
        if changed == None:
            continue

         else:

            #code to update the MainModel with user's approved suggestions
            # I create a dictionary with all the changes before updating so I hit the db only once.

         #after all this, I can say form.is_valid and update the suggestion as approved.

As i told before, there are probably better ways of doing this, but, this works.

Thanks

  • Related