django - form.cleaned_data[] for all fields in model - python

I am using django to digitalise a form. This form is a little bit complex, and there are a lot of fields in it. I was wondering if Django could do form.cleaned_data[] for all fields, in stead of declaring variables like obj.fieldname = form.cleaned_data['fieldname'] for each field apart.
I tried it with a forloop in the views.py, but that won't work
This is the forloop I'm talking about:
def get_form_naw(request):
if request.method == 'POST':
form = Form1(request.POST)
if form.is_valid():
for x in Model1():
formname = x.name
o = Model1()
o.formname = form.cleaned_data[formname]
o.save()
else:
form = Form1
return render(request, 'folder/home.html', context=locals())
I'm using a mysql database. My forms are declared like this:
forms.py
class Form1(forms.ModelForm):
class Meta:
model = Model1
exclude = ('id')

You shouldn't have to loop through the fields. You are using a model form, so you should just save the form:
if form.is_valid():
obj = form.save()
...
If you really need to set fields dynamically, you can use setattr.
fieldname = 'username'
value = 'my_user'
setattr(obj, fieldname, value)

you can get the instance of the data before saving like this:
if form.is_valid():
obj = form.save(commit=False) #get instance without saving
# do your thing
obj.save() #save into database

Related

Saving values to django model through a for loop

I want to use a dictionary to store values in a model through a modelform and a view. Today I solve it like this:
form.variable_1 = dictionary['variable_1']
form.variable_2 = dictionary['variable_2']
form.variable_3 = dictionary['variable_3']
form.variable_4 = dictionary['variable_4']
form.variable_5 = dictionary['variable_5']
form.variable_6 = dictionary['variable_6']
The keys in the dictionary are identical to the field names for the values I want to store. I would like to make the function a bit more pythonic - something like this:
for field in form:
form.field = dictionary['field']
However, I'm not sure how to use the Django ORM to achieve this. The fields I want to iterate are numbered 3-28 in the list of fields, so I guess I would have to slice the fields somehow and create a list based on that?
edit:
models.py
class MyModel(Model):
user = ForeignKey(settings.AUTH_USER_MODEL, on_delete=CASCADE)
Instance_name = CharField(max_length=200, default='')
Instance_text = TextField(default='')
variable_1 = IntegerField(null=True)
There's a total of 30 variables like variable 1 following it.
forms.py:
class MyModelMF(ModelForm):
class Meta:
model = MyModel
fields = [
'Instance_name',
'Instance_text'
]
widgets = {
'Instance_text': Textarea(attrs={"style": "height:4em;" "width:25em;"})
}
views.py (up until iteration starts, excluded return render etc for simplicity)
def create_instance(request):
form = MyModelMF()
if request.method == 'POST':
form = MyModelMF(request.POST)
if form.is_valid()
form = form.save(commit=False)
form.user = request.user
form.variable_1 = scores_dict['variable_1']
You can use the built-in function setattr to set an attribute of your instance by name. Iterate over the keys and values in your dict and use the keys as the attribute names when calling setattr
if form.is_valid()
form = form.save(commit=False)
form.user = request.user
for field_name, value in scores_dict.items():
setattr(form, field_name, value)
form.save()

Django relationship in manyToMany models, object has no attribute

I have a problem with creating relationship in m2m models.
models.py
class ECG(models.Model):
procedure= models.ManyToManyField('Procedure')
...
class Procedure(models.Model):
basic_info= models.IntegerField(default=0)
views.py
def newECG(request, procedure_id):
if request.method == 'POST':
form = NewECG(request.POST)
if form.is_valid():
form.save()
info = IncomingProcedure.objects.get(id=procedure_id)
form.procedure.add(info) #HERE IS A PROBLEM
return HttpResponseRedirect('/system/')
else:
form = NewECG()
return render(request, 'system/ecg.html', {'form': form})
forms.py
class NewECG(ModelForm):
class Meta:
model = ECG
exclude = ['procedure']
# fields = '__all__'
fields = [ ... ] # rest fields, except procedure
Procedure already exists. I need to create newECG in relation with procedure. ECG form is saving in db. Problem is when i want to use add() function.
ERROR :'NewECG' object has no attribute 'procedure', exception location: views.py
The ModelForm instance does not have the procedure attribute that is defined on the model. The ECG model instance, however, which is returned by the form's save(...) method, does have it:
ecg_instance = form.save()
info = IncomingProcedure.objects.get(id=procedure_id)
# info = Procedure.objects.get(id=procedure_id)
ecg_instance.procedure.add(info)
You just forgot a step:
def newECG(request, procedure_id):
if request.method == 'POST':
form = NewECG(request.POST)
if form.is_valid():
ecg = form.save()
info = IncomingProcedure.objects.get(id=procedure_id)
ecg.procedure.add(info) #HERE IS A PROBLEM
return HttpResponseRedirect('/system/')
I can't understand why you are trying to add IncomingProcedure.objects to your from in views.py
If you want save it on your database, Should simply do this:
views.py
# ... Your codes:
M = form.save() # save your class instance to M variable
info = IncomingProcedure.objects.get(id=procedure_id)
M.procedure.add(info) # save procedure instance to your object(An ECG model instance)

Post method in Django models

I am new in Django forms and I need to insert/update some data into my database.
I have some model and in the django admin panel I introduce manually the user's phone and the IMEI number.
After that I create a form, a template.html and a view.
The form is as follows:
from django import forms
class Send2phone(forms.Form):
NumberOfCalls = forms.CharField(
min_length=1,
widget=forms.TextInput({'class': 'form-control'})
)
TimeBetweenCalls = forms.CharField(
widget=forms.TextInput({'class': 'form-control'})
)
PSAP = forms.CharField(
min_length=1,
widget=forms.TextInput({'class': 'form-control'})
)
And my view is:
def phone_config(request):
if request.method == 'POST':
form = Send2phone(request.POST)
if form.is_valid():
cleaned_data = form.cleaned_data
NumberOfCalls = cleaned_data.get('NumberOfCalls')
TimeBetweenCalls = cleaned_data.get('TimeBetweenCalls')
PSAP = cleaned_data.get('PSAP')
phone_model = Phone()
phone_model.id = 1
phone_model.user = donothing
phone_model.imei = donothing
phone_model.num_calls = NumberOfCalls
phone_model.time_btwn_calls = TimeBetweenCalls
phone_model.psap = PSAP
phone_model.save()
return redirect(reverse('gracias'))
else:
form = Send2phone()
return render(request, 'heroconfigurer/heroconfigurer.html', {'form': form})
def gracias_view(request):
return render(request, 'heroconfigurer/gracias.html')
My problem comes now when I create the view. First of all, I check if the method is post and I get the data from the form.
Then I check if the form is valid and I create the object Phone. After that assign the different parameters and save them.
Inserting the data from the form is working good but imei and user ara being deleted if I don't specify them.
How can I insert data in the database models where exist some users and imeis? For example in id=1 I already have a user and an imei and I want to keep them
Existing fields are erased because you're creating new Phone object with existing id. You should instead retrieve existing Phone model and update it:
phone_model = Phone.objects.get(id=1)
phone_model.num_calls = NumberOfCalls
phone_model.time_btwn_calls = TimeBetweenCalls
phone_model.psap = PSAP
phone_model.save()
Or update it using queryset update method:
Phone.objects.filter(id=1).update(
num_calls=NumberOfCalls,
time_btwn_calls=TimeBetweenCalls,
psap=PSAP,
)
First one will touch database twice. Once for loading existing phone, and then for saving new values. Second will touch database only once, updating fields without touching rest of them.
You should be retrieving the existing Phone object and updating it where necessary.
if form.is_valid():
number_of_calls = form.cleaned_data.get('NumberOfCalls')
time_between_calls = form.cleaned_data.get('TimeBetweenCalls')
psap = form.cleaned_data.get('PSAP')
phone = Phone.objects.get(pk=1)
phone.num_calls = number_of_calls
phone.time_btwn_calls = time_between_calls
phone.psap = psap
phone.save()
Even better, make your form a ModelForm, and include only the fields you want to update:
class Send2phone(forms.ModelForm):
class Meta:
model = Phone
fields = ['num_calls', 'time_btwn_calls', 'psap']
now your view is just:
phone = Phone.objects.get(pk=1)
if request.method == 'POST':
form = Send2tcu(request.POST, instance=phone)
if form.is_valid():
form.save()
return redirect(reverse('gracias'))
else:
form = Send2tcu(instance=phone)
return render(request, 'heroconfigurer/heroconfigurer.html', {'form': form})

django dynamic forms - Dynamic ChoiceField

In django, how can I make a selectible formField to access the db for every time it is being calld?
Right now the line :
status = forms.ChoiceField(choices=FormsTools.StatusesToTuples(Status.objects.all()))
is executed once django is loaded and not every time the form is being showed.
How can I make the field dynamic ? so every time the form is being showed the selectible field will have values from db?
UPDATE:
POST data:
.
status: u'4'
.
.
in the Model, the field looks like this: status = models.IntegerField()
The View:
def edit_call(request, call_id):
c = Call.objects.get(id=call_id)
if request.POST:
form = CallForm(request.POST, instance=c)
print form.errors
if form.is_valid():
form.save()
return HttpResponseRedirect('/ViewCalls/')
else:
form = CallForm(instance=c)
args = {}
args.update(csrf(request))
args["form"] = form
args["id"] = call_id
t = get_template('edit_call.html')
cont = RequestContext(request, args)
html = t.render(cont)
return HttpResponse(html)
The form:
simple as:
class CallForm (forms.ModelForm):
employee_id = forms.ModelChoiceField(queryset=Employee.objects.all())
status = forms.ModelChoiceField(queryset=Status.objects.all())
class Meta():
model = Call
You need to call the contructor each time you load the form to update the choices. So the form should be:
class CallForm(forms.ModelForm):
...
status = forms.ChoiceField()
def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
initial=None, error_class=ErrorList, label_suffix=None,
empty_permitted=False):
super(CallForm, self).__init__(data, files, auto_id, prefix, initial, error_class,
label_suffix, empty_permitted)
self.fields['status'].choices = FormsTools.StatusesToTuples(Status.objects.all())
Have you looked at forms.ModelChoiceField?
UPDATED ANSWER FOLLOWING UPDATED QUESTION:
You now need to get your models and your forms to match:
Your model has an IntegerField, your form has a ModelChoiceField. The latter returns a pk string, not an integer ID.
Given that you're using a modelform, why not just let it do the work of creating the fields for you?
class CallForm(forms.ModelForm):
class Meta:
model = Call
fields = ('employee', 'status') # assuming these are what the field names are

Django form fields do not get populated by POST data

I have a model form with custom constructor. It checks if a file is required and if false, it deletes the file field. It also has two hidden fields, which I initialize at my views. The form class is as follows:
class SubmitTask(forms.ModelForm):
task = forms.ModelChoiceField(queryset=Task.objects.all(), widget=forms.HiddenInput())
student = forms.ModelChoiceField(queryset=UserProfile.objects.all(), widget=forms.HiddenInput())
def __init__(self, file_required=False, *args, **kwargs):
super(SubmitTask, self).__init__(*args, **kwargs)
if file_required is True:
file = forms.FileField(
label='Select a file',
help_text='max: 2.5 MB'
)
else:
del self.fields['file']
class Meta:
model = Submission
exclude = ('date_submitted',)
My problem is that the hidden fields are populated when I initialize the form (I have confirmed that its values are indeed initialized by viewing the HTML code). However, the values of the hidden fields are not populated during POST request. I have confirmed during POST request that the form is indeed bound and I also confirmed on Firebug that POST also contains the task and student values. This is the involved method in my views.py
def view_task(request, id):
task = Task.objects.get(pk=id)
profile = request.user.get_profile()
data = {}
data['classroom'] = task.get_classroom()
data['description'] = task.get_description()
teacher_classrooms = Classroom.objects.filter(teacher=profile)
teacher_tasks = Task.objects.filter(classroom__in=teacher_classrooms)
if not submission and task not in teacher_tasks:
form = SubmitTask(file_required=task.file_required, initial={'task':task.pk, 'student':profile.pk})
data['form'] = form
if request.method == 'POST':
form = SubmitTask(request.POST, request.FILES)
if form.is_valid():
form.save()
return render_to_response('classrooms/view_task.html',
data, context_instance=RequestContext(request))
Your view function looks incorrect to me:
Where does the submission variable come from, when initializing the posted form you are missing the file_required parameter and the form processing should perhaps be reorganized to something like:
if request.method == 'POST':
form = SubmitTask(task.file_required, request.POST, request.FILES)
...
else:
form = SubmitTask(task.file_required, ...)
data['form'] = form

Categories