Как динамически получить доступ к полю в форме django для изменения экземпляра
Используя общий CreateView в Django, я пытаюсь сохранить только те поля, которые были изменены пользователем.
Я пытаюсь сделать это в своем представлении:
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
В последней строке я получил эту ошибку:
у объекта нет атрибута 'field'
Есть ли способ динамического доступа к каждому полю в форме, чтобы я мог изменить его?
Есть ли способ динамического доступа к каждому полю в форме. Да.
form.fields[field_name]
Значит, я могу его изменить? Да.
form.fields[field_name] = django.forms.Charfield(required=False)
Но в вашем коде, вероятно, вы хотите добиться значения поля:
field_value = form[field_name].value
Если у вас есть поле, ограниченное данными, вы можете изменить также данные формы:
form.data(form.add_prefix(field_name)) = new_value
Но это уже неправильный подход, чтобы что-то здесь изменить.
Я могу представить: в вашем случае вы не понимаете, как форма / modelform сохраняет данные, и поэтому хотите сделать что-то ненужное:
Еще раз, как ModelForm
"сохраняет" данные в БД:
- Форма проверки данных.
- Форма очищает данные.
- on form.save(**kwargs) - Форма создает экземпляр и:
- вызвать instance.save(), если form.save(commit=True)
- не вызывать instance.save(), если form.save(commit=False)
- Инстанция сохраняет данные.
Форма сама ничего не сохраняет, instance.save
- Там есть все, что вам нужно.
instance.save(self, force_insert=False, force_update=False, using=None, update_fields=None)
В вашем случае вы используете CreateView - там все поля должны быть инициированы, вы не можете UPDATE что-то, это что-то еще не существует. Вы можете только избегать пустых значений, если хотите.
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)
последний: form.instance.field
смешно
form
имеет поля. Вы можете достичь каждогоfield
по имени.Model class
имеет поля. Вы можете достичь каждогоfield
по имени.instance
имеет атрибуты или свойства. Вы можете достичь каждогоattribute
по имени.
А прямо сейчас: что вы действительно хотите сделать?
Я пытаюсь обновить объекты в Модели, но не напрямую за один шаг. Мне нужно, чтобы когда пользователь хочет обновить объект, он мог предложить некоторые изменения, но перед обновлением объекта другой пользователь должен одобрить его предложения перед сохранением изменений.
Поскольку модель имеет много полей и изменения могут затронуть только те поля, которые были отредактированы, я хочу изменять только отредактированные поля.
Наверное, это не лучший подход, но вот что я сделал:
Я создал вторую модель, чтобы сохранить предложения по изменению, поэтому у меня есть две модели, выглядящие почти одинаково:
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)
и в представлениях я получил поле "одобрено" в форме, если пользователь выбрал "True", я обращаюсь к каждому полю в MainModel и проверяю, содержит ли предложение какие-либо изменения, если да, я изменяю его в MainModel. Наконец, я обновляю модель SuggestionsModel.
Я все еще работаю над этим. На данный момент у меня есть что-то вроде этого в 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.
Как я уже говорил, возможно, есть лучшие способы сделать это, но этот работает.
Спасибо