django saving form field in generic or functional view - python

Lets say I have a form and its files are user, value, age
I am using generic or functional view... so how can I do like
def SomeView(request):
mod = MyModel()
mod.user = request.user
mod.value = form.cleaned_data["value"]
mod.save()
I think mod.value = form.cleaned_data["value"] can only be done with class based view. But how can I do this in generic or functinal view.

If you need to do it with functional views, you need to check the request.POST
def SomeView(request)
c = RequestContext(request, {})
if request.method == 'POST' :
form = YourForm(request.POST or None )
# your code here,
# redirect on success probably
else :
# create blank form
form = YourForm(None)
c[form]=form
return render_to_response("path/to/your/templet.html", c)

You can get value data from request(GET or POST) - request.GET.get('value', 'default_value') or request.POST.get('value', 'default_value')

Related

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

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

How to pass data between django views

This questions addresses my question genearally, but I am looking for a more specific explanation.
I would like a user to update a a group of model objects, however, the queryset for these objects will need to be retrieved first. My plan is to do this in two seperate URs/views, getting the query set info from the first, then displaying the model formset to be updated next.
My first view gives a list of all the the "Project"s (One of my models), and retrieves the id of the project selected.
Here is the form:
class ProjectLookupForm(forms.Form):
Project_Name = chosenforms.ChosenModelChoiceField(queryset=Project.objects.all())
and here is the view:
def update_project_filter(request):
project_form = ProjectLookupForm(request.POST or None)
if request.method == 'POST':
if project_form.is_valid():
context = {"project_form":project_form}
# Get project here and share it with the next view.
selected_project_id = project_form.cleaned_data["Project_Name"].id
# Add a new return statement here?
# Or call update project view from here?
# Add a redirect button to html?
else:
errors = project_form.errors
context = {"errors":errors, "project_form":project_form}
else:
context = {"project_form":project_form}
return render(request, 'filter_update_project_form.html', context)
As one can see, I have included some comments brainstorming what my possibilities are. My goal is to send the selected_project_id to this next view, so that it can use that id as a model form query set.
def update_project(request):
UpdateFormset = modelformset_factory(Sample, fields=("sample_name", "extraction_date",
"project", "order", "notebook", "notebook_page"))
if request.method == 'POST':
formset = UpdateFormset(request.POST, request.FILES)
if formset.is_valid():
formset.save()
context = {"formset": formset, "project_form":project_form}
else:
errors = formset.errors
context = {"formset":formset, "errors":errors, "project_form":project_form}
else:
formset = UpdateFormset(queryset=Sample.objects.filter(project=2))
context = {"formset":formset, "project_form":project_form}
return render(request, 'update_project_form.html', context)
One can see here that I have hard coded the queryset like so:
queryset=Sample.objects.filter(project=2)
How can I set "project=" to my selected_project_id? Do I pass this info to the view as an input parameter? Or do I send it to the next URL and take it from there?
Assuming you've activated django.contrib.sessions.middleware.SessionMiddleware; you can pass data between views using request.session dictionary as follows:
def update_project_filter(request):
...
selected_project_id = project_form.cleaned_data["Project_Name"].id
request.session['selected_project_id'] = selected_project_id
...
def update_project(request):
...
selected_project_id = request.session.get('selected_project_id')
...

Preserve checked checkboxes after post in django

I want to keep the form fields preserved after submitting the form. I can preserve all the fields except the checked checkboxes
Here is my form action view:
def student_submit_info(request):
form_values = {}
if request.method == 'POST':
form = StudentForm(request.POST)
print form.is_valid()
form_values = getDetails(request)
if form.is_valid():
print request.user.username
student = Student.objects.get(user=request.user)
// saving student to DB
saveDetails(request, student, form_values)
return render_to_response('student.html', form_values, context_instance=RequestContext(request))
def getDetails(request):
#fetch input data
form_values = {}
form_values['first_name'] = request.POST['first_name']
form_values['last_name'] = request.POST['last_name']
form_values['skills'] = request.POST.getlist('skills[]')
return form_values
I would want to preserve skills (checkbox), here's a part of my template
skill1<input type="checkbox" name="skills[]" checked value="skill1"/>
skill2<input type="checkbox" name="skills[]" value="skill2"/>
skill3<input type="checkbox" name="skills[]" value="skill3"/>
You should make a custom django Forms to handle easily forms, example of a post view:
def post_view(request):
form = MyForm(request.POST)
if form.is_valid():
do_something()
render(request, 'your_temp', {'MyForm': MyForm'})
With this kind of snippet, data in form will always be those sent.
You can override is_valid() for empty skill checkboxes.
Perhaps, use CBV's and ModelForms to make the process simpler.
Combine a listview (or similar) and add your form via context.
Then in get_context_data of your CBV:
form_values = {}
#Simpler code below for accessing post dictionary
for key, value in self.request.POST.items():
if value == 'on':
form_values[key] = value
context = super().get_context_data(**kwargs)
# You need to add form_values to make it accessible in the forms.py
context['form'] = YourFormName(form_values)
Then, in your forms.py (I'm hoping you use modelforms):
def __init__(self, filters, *args, **kwargs):
super(YourFormName, self).__init__(*args, **kwargs)
if len(form_values) > 0:
for field_name in self.fields:
if field_name in filters:
self.fields[field_name].widget = forms.CheckboxInput(attrs={'checked': True})
I hope this helps.

Relationship between form and formset on same webpage

I'm trying to relate all the objects created in a formset to an object created on the same webpage as the formset. So, an example of the code is this:
def create_b(request):
SpeciesFormSet = modelformset_factory(Species, fields=('common', 'scientific'))
if request.method == 'POST':
formset = SpeciesFormSet(request.POST)
form1 = BForm(request.POST)
if form1.is_valid():
objcreate = BModel.objects.create(
name = form1.cleaned_data['name'],
...
)
objcreate.save()
for forms in formset.forms:
if forms.is_valid():
formset1 = Species.objects.create (
common = forms.cleaned_data['common'],
scientific = forms.cleaned_data['scientific'],
BName = form1.cleaned_data['name']
)
formset1.save()
else:
formset = SpeciesFormSet()
form1 = BForm()
c = {'SpeciesFormSet' : SpeciesFormSet, 'form1' : form1}
c.update(csrf(request))
return render_to_response('Forms/create_b.html', c)
return HttpResponseRedirect('/accounts/profile')
else:
formset = SpeciesFormSet()
form1 = BForm()
c = {'SpeciesFormSet' : SpeciesFormSet, 'form1' : form1}
c.update(csrf(request))
return render_to_response('Forms/create_b.html', c)
The problem I'm having is that when trying to relate the formset object to the form one, it tells me that the form object doesn't actually exist. It creates the object in the database however, just none of the formset objects. I get the error "Cannot assign "u''": "Species.BName" must be a "BModel" instance." if that helps. Also, the relationship is a ForeignKey. Is there anyway to solve this? Thanks for your time.
This exact pattern is what inline model formsets are for.
From the error, it looks like you are assigning a BName where the property is supposed to be a BModel. Either, you want to change the BName with a BModel, or you need to fix your models so they match with a BName for the Species.
formset1 = Species.objects.create (
common = forms.cleaned_data['common'],
scientific = forms.cleaned_data['scientific'],
BName = form1.cleaned_data['name']
)
formset1.save()

Django set default form values

I have a Model as follows:
class TankJournal(models.Model):
user = models.ForeignKey(User)
tank = models.ForeignKey(TankProfile)
ts = models.IntegerField(max_length=15)
title = models.CharField(max_length=50)
body = models.TextField()
I also have a model form for the above model as follows:
class JournalForm(ModelForm):
tank = forms.IntegerField(widget=forms.HiddenInput())
class Meta:
model = TankJournal
exclude = ('user','ts')
I want to know how to set the default value for that tank hidden field. Here is my function to show/save the form so far:
def addJournal(request, id=0):
if not request.user.is_authenticated():
return HttpResponseRedirect('/')
# checking if they own the tank
from django.contrib.auth.models import User
user = User.objects.get(pk=request.session['id'])
if request.method == 'POST':
form = JournalForm(request.POST)
if form.is_valid():
obj = form.save(commit=False)
# setting the user and ts
from time import time
obj.ts = int(time())
obj.user = user
obj.tank = TankProfile.objects.get(pk=form.cleaned_data['tank_id'])
# saving the test
obj.save()
else:
form = JournalForm()
try:
tank = TankProfile.objects.get(user=user, id=id)
except TankProfile.DoesNotExist:
return HttpResponseRedirect('/error/')
You can use Form.initial, which is explained here.
You have two options either populate the value when calling form constructor:
form = JournalForm(initial={'tank': 123})
or set the value in the form definition:
tank = forms.IntegerField(widget=forms.HiddenInput(), initial=123)
Other solution: Set initial after creating the form:
form.fields['tank'].initial = 123
If you are creating modelform from POST values initial can be assigned this way:
form = SomeModelForm(request.POST, initial={"option": "10"})
https://docs.djangoproject.com/en/1.10/topics/forms/modelforms/#providing-initial-values
I had this other solution (I'm posting it in case someone else as me is using the following method from the model):
class onlyUserIsActiveField(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(onlyUserIsActiveField, self).__init__(*args, **kwargs)
self.fields['is_active'].initial = False
class Meta:
model = User
fields = ['is_active']
labels = {'is_active': 'Is Active'}
widgets = {
'is_active': forms.CheckboxInput( attrs={
'class': 'form-control bootstrap-switch',
'data-size': 'mini',
'data-on-color': 'success',
'data-on-text': 'Active',
'data-off-color': 'danger',
'data-off-text': 'Inactive',
'name': 'is_active',
})
}
The initial is definded on the __init__ function as self.fields['is_active'].initial = False
As explained in Django docs, initial is not default.
The initial value of a field is intended to be displayed in an HTML . But if the user delete this value, and finally send back a blank value for this field, the initial value is lost. So you do not obtain what is expected by a default behaviour.
The default behaviour is : the value that validation process will take if data argument do not contain any value for the field.
To implement that, a straightforward way is to combine initial and clean_<field>():
class JournalForm(ModelForm):
tank = forms.IntegerField(widget=forms.HiddenInput(), initial=123)
(...)
def clean_tank(self):
if not self['tank'].html_name in self.data:
return self.fields['tank'].initial
return self.cleaned_data['tank']
If you want to add initial value and post other value you have to add the following :
or None after request.POST
form = JournalForm(request.POST or None,initial={'tank': 123})
If you want to add files or images also
form = JournalForm(request.POST or None,request.FILES or None,initial={'tank': 123})
I hope this can help you:
form.instance.updatedby = form.cleaned_data['updatedby'] = request.user.id
I also encountered the need to set default values in the form during development. My solution is
initial={"":""}
form=ArticleModel(request.POST)
if form.has_changed():
data = {i: form.cleaned_data[i] for i in form.changed_data}
data.update({key: val for key, val in init_praram.items() if key not in form.changed_data})
use form.has_changed ,if form.fields is required you can use this method
How I added the initial to the form:
I read #Sergey Golovchenko answer.
So I just added it to the form in if request.method == 'POST':.
But that's not where you place it, if you want to see what value it got before posting the form.
You need to put it in the form where the else is.
Example here from views.py
def myForm(request):
kontext = {}
if request.method == 'POST':
# You might want to use clean_data instead of initial here. I found something on a stack overflow question, and you add clean data to the Forms.py, if you want to change the post data. https://stackoverflow.com/questions/36711229/django-forms-clean-data
form = myModelForm(request.POST, initial={'user': request.user})
if form.is_valid():
form.save()
return redirect('/')
else:
# you need to put initial here, if you want to see the value before you post it
form = myModelForm(initial={'user': request.user})
kontext['form'] = form
return render(request, 'app1/my_form.html', kontext)

Categories