Submitting Django Form In Custom HTML - django-forms

I am a newb to django forms and I am trying to create a very specific user interface, so I can't use model forms (or can I?)
I created a custom form that looks like this:
but it won't commit to the db?
This is my html form:
<form method="POST" action='/create/' id="big_idea_form" class="tabscontent">{% csrf_token %}
<label class="tabpage" id="tabpage_1" ><span>next</span><p>Give it a name!</p><input type="text" id="name" placeholder="Type your title here" onblur='changeIt("name", "name_span")'/></label>
<label class="tabpage" id="tabpage_2" ><p>What is it about?</p><input type="text" id="subtitle" name="subtitle" placeholder="Type your subtitle here" onblur='changeIt("subtitle", "subtitle_span")'/></label>
<label class="tabpage" id="tabpage_3" ><p>Why is it important?</p><textarea id="description" name= "description" cols="42" rows="5" placeholder="this can be any description but it becomes more interesting if you can explain why it is important as part of your description" onblur='changeIt("description", "description_span")'></textarea></label>
<label class="tabpage" id="tabpage_4" ><p id="success_title">What is considered success?</p><textarea id="success" name="success" cols="42" rows="5" placeholder="describe what sucess means to your students... what does mastery look like?" onblur='changeIt("success", "success_span")'></textarea></label>
<input type="submit" value="Submit"/>
</form>
This is my form:
from django import forms
import urlparse
from models import Lesson
class CreateLesson(forms.Form):
name=forms.CharField()
subtitle=forms.CharField(required=False)
creator=forms.CharField() #automate
description=forms.CharField()
success=forms.CharField()
unit=forms.CharField(required=False)
public=forms.BooleanField()
def save(self, request):
data=self.cleaned_data
Lesson.creator = request.user
Lesson.name=data.get('name', '')
Lesson.subtitle=data.get('subtitle', '')
Lesson.topic=data.get('topic', '')
Lesson.description=data.get('description', '')
Lesson.unit=data.get('unit', '')
Lesson.public=data.get('public', True)
Lesson.save()
return Lesson
And here is my view:
from django.shortcuts import render
from django.http import HttpResponseRedirect
from forms import CreateLesson
def Create_Lesson(request):
if request.method == 'POST': # If the form has been submitted...
form = CreateLesson(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
form.save()
return HttpResponseRedirect('/create/') # Redirect after POST
else:
form = CreateLesson() # An unbound form
return render(request, 'create_lesson/new_ideas.html', {
'form': form,
})

problem was that the form was not validating because there were fields in the model not represented on the form...
i simplified the form by using ModelForm and exclude as such
forms.py
class CreateLessonModel(forms.ModelForm):
class Meta:
model = Lesson
exclude =('unit', 'slug', 'topic', 'public', 'created_date', 'creator')
views.py
from django.shortcuts import render
from django.http import HttpResponseRedirect
from forms import CreateLessonModel
from django.template.defaultfilters import slugify
def Create_Lesson(request):
if request.method == "POST": # If the form has been submitted...
form = CreateLessonModel(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
lesson = form.save(commit=False)
lesson.creator = request.user
lesson.slug = slugify(lesson.name)
lesson.save()
return HttpResponseRedirect('') # Redirect after POST
else:
form = CreateLessonModel() # An unbound form
return render(request, 'create_lesson/new_ideas.html', {
'form': form,
})

Related

Django Custom Form not saving data to Database

I am new to Django.I know this question has been asked here several times but none of the solutions presented worked for me. I am creating a custom user registration form. The form is rendering correctly but it is not posting data to database upon submission. It just refreshes and wipes out the data inputted. I have been cracking my head for the last several hours but i cannot point out where the issue is in this code. Your kind assistance will be appreciated sincerely. Thanks
My view is as follows
```from django.shortcuts import render, redirect
from users.forms import RegistrationForm
from django.contrib import messages
def register(request):
"""Registration view"""
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
username = form.cleaned_data('username')
messages.success(request, f'Account created for{username}!')
form.save()
return redirect('bookings-home')
else:
print (form.errors)
else:
form = RegistrationForm()
return render(request, 'users/register.html', {'form': form})
```
**My Form is as follows**
```from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
class RegistrationForm(UserCreationForm):
"""Handles users registration"""
email = forms.EmailField(required=True)
class Meta:
"""Defines fields needed"""
model = User
fields = (
'username',
'first_name',
'last_name',
'email',
'password1',
'password2'
)
def save(self, commit=True):
"""Save data to the database if safe"""
user = super(RegistrationForm, self).save(commit=False)
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
user.email = self.cleaned_data['email']
if commit:
user.save()
return user
```
**My template code is as follows**
```<form method="POST" action = '.'>
{% csrf_token %}
<div class="form-inner">
<div class="login-with-socials">
<button class="btn btn-facebook btn-block">Register with Facebook</button>
<!-- <button class="btn btn-google btn-block">Register with Google</button> -->
<button class="btn btn-twitter btn-block">Register with Twitter</button>
<!-- <button class="btn btn-pinterest btn-block">Register with Pinterest</button> -->
</div>
<div class="text-seperator">
<span>or</span>
</div>
{% for field in form %}
<div class="form-group">
<input id="login_username" class="form-control" placeholder="{{field.label}}" type="{{ field.field.widget.input_type }}">
</div> {% endfor %}```
**And finally my url is as follows**
```from django.contrib import admin
from django.urls import path, include
from users import views as user_views
urlpatterns = [
path('admin/', admin.site.urls),
path('register/', user_views.register, name='register'),
path('', include('hotels.urls')),
]```
I was partly able to get a solution to the issue above by implementing crisp_forms. In the first instance i was attempting to use css with Django fields. I am still very curious to know why the above method is not working

django checkboxSelectMultiple

Something very strange is happening, I've built a MultipleChoiceField in forms.py that is rendering as a normal list. I am unable to have the checkboxes display. I'm hoping someone can spot where I might have gone wrong.
forms.py
from django import forms
from . import models
from behaviour.models import Interventions
class IncidentForm(forms.Form):
def __init__(self,*args,**kwargs):
self.request = kwargs.pop('request')
super(IncidentForm,self).__init__(*args, **kwargs)
intervention_set = Interventions.objects.filter(schoolid_id = self.request)
intervention_choice = []
for intervention in intervention_set:
intervention_choice.append((intervention.pk, intervention.name))
self.fields['intervention'].choices = intervention_choice
intervention = forms.MultipleChoiceField(label='Intervention', choices=(), widget=forms.CheckboxSelectMultiple(), required=True,)
incident.html
<div>
<label class="control-label">{% trans 'Intervention' %}</label><br />
{{ form.intervention }}
<small class="form-control-feedback"> {{ form.intervention.errors }} </small>
</div>
HTML output
<div>
<label class="control-label">Intervention</label><br>
<ul id="id_intervention">
<li><label for="id_intervention_0"><input type="checkbox" name="intervention" value="3" id="id_intervention_0">
Communicate verbally with Parent</label>
</li>
<li><label for="id_intervention_1"><input type="checkbox" name="intervention" value="2" id="id_intervention_1">
Non-verbal signal</label>
</li>
<li><label for="id_intervention_2"><input type="checkbox" name="intervention" value="1" id="id_intervention_2">
Spoke with Student</label>
</li>
</ul>
<small class="form-control-feedback"> </small>
</div>
Screenshot of output
If you are using Django admin and you parent model is not using any relationship with child model but has charfield to store ids of selected items of child model that will be added to ModelAdmin as custom field.
Follow steps:
STEP 1: model.py
class yourparentmodel(models.Model):
...
prior_learning_checks = models.CharField(max_length=120, null = True, blank=True)
...
class childmodel(models.Model):
rpl_id = models.CharField(max_length=4, null = True, blank=True)
rpl_desc = models.CharField(max_length=120, null = True, blank=True)
Here in this example parent is CohortDetails as inline to Cohort, or can limit to Cohort only if don't need inlines.
and child model is StudentRPL here in this example.
STEP 2: admin.py
Add CheckboxSelectMultiple to list your table data that id and description in this example.
Then use init attach your custom field for child model with parent form.
class StudentRPLForm(forms.ModelForm):
student_prior_learning = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple(), queryset=StudentRpl.objects.all())
class Meta:
model = StudentRpl
fields = [
'rpl_indicator',
'rpl_description',
]
def __init__(self, *args, **kwargs):
super(StudentRPLForm, self).__init__(*args, **kwargs)
if self.instance and self.instance.pk:
self.fields['student_prior_learning']=forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple(), queryset=StudentRpl.objects.all())
rpl_list = []
ids = self.instance.prior_learning_checks
if ',' in ids:
ids = ids[0:(len(ids) - 1)]
rpl_list = ids.rsplit(',')
self.fields['student_prior_learning'].initial = StudentRpl.objects.filter(rpl_indicator__in=rpl_list)
Now it is time to save data by overriding save(self, commit).
Make sure use the cleaned_data. this is magic to collect only checked rows data and save to charfield of your parentmodel to read it again when to load the change_form. Because you are saving as comma separared ids, you have chance to load this string into list and filter your custom child model.
Other magic to view last saved ids in commas by assigning:
self.fields['student_prior_learning'].initial value to your filtered data in init function above (as i did)!!!
def save(self, commit=True, *args, **kwargs):
m = super(StudentRPLForm, self).save(commit=False, *args, **kwargs)
selected_rpl_list = ''
if self is not 'CohortDetailsForm':
for cr in self.cleaned_data['student_prior_learning']:
selected_rpl_list += cr.rpl_indicator + ','
m.prior_learning_checks = selected_rpl_list
if commit:
m.save()
STEP 3: admin.py
Assign your form to Inline or directly to modeladmin class if you don't need inlines.
class CohortDetailInline(admin.StackedInline):
model = CohortDetails
form = StudentRPLForm
fieldsets = ['fields':, ('student_prior_learning')]
.....
#admin.register(Cohort)
class CohortAdmin(admin.ModelAdmin):
inlines = CohortDetailInline
....
DONE !!!!

Django 1.11 Template not rendering MultipleChoiceField correctly which is working with django 1.4

I'm trying to upgrade existing application from version 1.4 to 1.11.
I have an issue where MultipleChoiceField is getting stored in database but template does not render those as being checked.
models.py
class TestModel(models.Model):
test = models.CharField(blank=True, max_length=200)
forms.py
from django import forms
from django.forms import ModelForm
from app.models import TestModel
CHOICES = (
('1', 'Select All'),
('a', 'choice 1'),
('k', 'choice 2'),
)
class TestForm(ModelForm):
test = forms.MultipleChoiceField(choices=CHOICES, required=False, widget=forms.CheckboxSelectMultiple()
)
class Meta:
model = TestModel
fields = '__all__'
form1 = TestForm(data={'test': ['a','k']})
When I run this using the manage.py shell I get the correct HTML output
print form1
<tr>
<th><label>Test:</label></th>
<td>
<ul id="id_test">
<li>
<label for="id_test_0"><input type="checkbox" name="test" value="1" id="id_test_0" onclick="selectAll(this);" />Select All</label>
</li>
<li>
<label for="id_test_1"><input type="checkbox" name="test" value="a" checked id="id_test_1" onclick="selectAll(this);" />choice 1</label>
</li>
<li>
<label for="id_test_2"><input type="checkbox" name="test" value="k" checked id="id_test_2" onclick="selectAll(this);" />choice 2</label>
</li>
</ul>
</td>
</tr>
You can see that it has the checked attribute in the code.
Template
<div id="Scrolldrive2">{{form1.test}}</div>
The selected checkboxes are not rendered on the UI.
Issue was due to initial data returned from model was of type string
eg. form1 = TestForm(initial={'test': u"[u'a', u'k']"})
Django 1.4 could convert data to list internally which was not happening with 1.11.Have converted initial data to list and now it is working fine.
Working snippet which renders a 'test' field data as list type instead of string type in forms.py
import json
def jsonify(data):
return json.loads(data.replace("u'", "'").replace("'", '"'))
#output is [u'a', u'k']
class TestForm(ModelForm):
test = forms.MultipleChoiceField(choices=CHOICES, required=False,
widget=forms.CheckboxSelectMultiple())
class Meta:
model = TestModel
fields = '__all__'
def __init__(self, *args, **kwargs):
super(TestForm, self).__init__(*args, **kwargs)
if self.instance:
obj_data = self.instance.__dict__
self.initial['test'] = jsonify(obj_data['test'])

How to correctly reference the User model in a form

Basically I'm trying to offer a feature for my site where one can register an electric imp(more than one) to their user account. My issue is that my Device model, and by extension my DeviceForm ModelForm uses a ForeignKey to reference the user object. So when I go to register a device it asks for the name of the device, the imp's agent_id, the device type and the user to associate with the account. I think where my is_valid() validation is failing is with how I reference the User model. I don't think its a "valid" input for the user object. Is there a different way to use the User's username to link the device to the correct account?
Models.py:
class Device(models.Model):
name = models.CharField(max_length=100)
agent_id = models.CharField(max_length=100)
device_type = models.CharField(max_length=100, choices=(
("imp", "Electric Imp P3V3"),
))
owner = models.ForeignKey(User)
def __unicode__(self):
return self.name
class DeviceForm(ModelForm):
class Meta:
model = Device
fields = ['name', 'agent_id', 'device_type', 'owner']
def clean_agent_id(self):
agent_id = self.cleaned_data['agent_id']
if Device.objects.exclude(pk=self.instance.pk).filter(agent_id=agent_id).exists():
raise forms.ValidationError(u'agent_id "%s" is already in use.' % agent_id)
return agent_id
Views.py:
def devices(request):
devform = DeviceForm(request.POST)
if devform.is_valid():
device_obj = devform.save()
device_obj.save()
return HttpResponseRedirect('deviceconfirmation')
else:
devform = DeviceForm()
return render_to_response('courses/devices.html', {'devform': devform}, context_instance=RequestContext(request))
devices.html:
{% extends "layout.html" %}
{% load static from staticfiles %}
{% block title %}{{ page.title }}{% endblock %}
{% block content %}
<article>
<div id="wrapper">
<p id="devicecreate">Register your device to your account:</p>
<form action="{% url 'courses:deviceconfirmation' %}" id="devform" method="post"> {% csrf_token %}
<p>
<label for="name">Device Name:</label>
<input id="name" name="name" type="text">
</p>
<p>
<label for="agent_id">Agent ID:</label>
<input id="agent_id" name="agent_id" type="text">
</p>
<p>
<label for="device_type">Imp Type:</label>
<select name="device_type" form="devform" id="selectbox">
<option value="imp">Imp Regular</option>
<option value="Electric Imp P3V3">Imp P3V3</option>
</select>
</p>
<p>
<label for="owner">Device Owner(username):</label>
<input id="owner" name="owner" type="text">
</p>
<p>
<input type="submit" value="REGISTER DEVICE" id="submit">
</p>
</form>
</div>
</article>
{% endblock %}
views.py for device confirmation:
def deviceconfirmation(request):
if request.method == 'POST':
try:
dev = Device.objects.get(agent_id=request.POST['agent_id'])
return render(request, 'courses/deviceconfirmation.html', {'dev': dev})
except Device.DoesNotExist:
return HttpResponseRedirect('invalidimp')
else:
raise Http404('Only POSTs are allowed')
urls.py:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.homepage, name='homepage'),
url(r'contact/$', views.contact, name='contact'),
url(r'login/$', views.login, name='login'),
url(r'products/$', views.products, name='products'),
url(r'register/$', views.register, name='register'),
url(r'register/thanks/$', views.thanks, name='thanks'),
url(r'register/inuse/$', views.inuse, name='inuse'),
url(r'login/accountinfo/$', views.accountinfo, name='accountinfo'),
url(r'devices/$', views.devices, name='devices'),
url(r'devices/deviceconfirmation/$', views.deviceconfirmation, name='deviceconfirmation'),
url(r'devices/deviceconfirmation/invalidimp/$', views.invalidimp, name='invalidimp'),
]
For when the logged in user adds a device to himself only: You can pass the current user as owner to the Form when you post. You don't need the owner initially in the form if not posting. In the form, override the save method and pass the owner before saving the device instance.
--
update based on comments:
amends to url for deviceconfirmation and view; url now accepts the device id. See bellow code updated
see also the template updated info
View (assuming def devices is used for both get and post):
def devices(request):
if request.method == 'POST":
devform = DeviceForm(request.POST, owner=request.user)
if devform.is_valid():
dev = devform.save()
return HttpResponseRedirect(reverse('deviceconfirmation', kwargs={'device_id': dev.id}))
else:
return render_to_response('courses/devices.html', {'devform': devform}, context_instance=RequestContext(request))
else:
devform = DeviceForm()
return render_to_response('courses/devices.html', {'devform': devform}, context_instance=RequestContext(request))
View deviceconfirmation:
def deviceconfirmation(request, device_id=None):
try:
dev = Device.objects.get(id=device_id)
return render(request, 'courses/deviceconfirmation.html', {'dev': dev})
except Device.DoesNotExist:
return HttpResponseRedirect('invalidimp')
Form:
class DeviceForm(ModelForm):
class Meta:
model = Device
fields = ['name', 'agent_id', 'device_type']
def __init__(self, *args, **kwargs):
owner = kwargs.pop('owner', None)
super(DeviceForm, self).__init__(*args, **kwargs)
self.owner = owner;
def clean_agent_id(self):
agent_id = self.cleaned_data['agent_id']
if Device.objects.filter(agent_id=agent_id).exists():
raise forms.ValidationError(u'agent_id "%s" is already in use.' % agent_id)
return agent_id
def save(self, commit=True):
device = super(DeviceForm, self).save(commit=False)
device.owner = self.owner
if commit:
device.save()
return device
Template:
delete the form action url in the template -> when you post, it will go to the same view from which you did the get (which is the devices view) ; <form action="" .....>
remove owner form field - to display current owner username, just use
{{request.user.username}}
URL:
url(r'devices/deviceconfirmation/(?P<device_id>\S+)/$', views.deviceconfirmation, name='deviceconfirmation'),

Unable to Save form Django

I am trying to save a form to update an existing user, but I am unable to get it to work. The error occurs when I try to save the form. The console shows the error occurs in the view (internal server error).
Form:
class updateFirstName(forms.ModelForm):
class Meta:
model = User
fields = ('first_name',)
def __init__(self, *args, **kwargs):
super(updateInfoForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_id = 'id-updateFirst'
self.helper.form_class = 'blueForms'
self.helper.form_method = 'post'
self.helper.form_action = '/login/userInfoChange/'
self.helper.add_input(Submit('submit', 'Submit'))
view:
#json_view
#csrf_exempt
def userInfoChange(request):
context = RequestContext(request)
if request.method == 'POST':
user = User.objects.get(username=request.user.username)
user_form = updateFirstName(request.POST)
print user_form
if user_form.is_valid():
user_form.save()
print "Valid Form"
return {'success': True}
html:
<form id="updateUsername">
<div class="input-group">
<span class="input-group-btn">
<button class="btn btn-success" type="button" id="submit-username">Change</button>
</span>
<input type="text" class="form-control" id="id_firstname" placeholder="First Name: {{user.first_name}}">
<script type="text/javascript">
$('#submit-username').click(function(){
$.ajax({//begin
type: 'POST',
url: '/login/userInfoChange/',
data: $('#updateUsername').serialize(),
success: function(result){
console.log('updateUsername');
}
});
});
</script>
</div><br></form>
Model:
class UserProfile(models.Model):
user = models.OneToOneField(User)
confirmation_code = models.CharField(max_length=128)
reset_code = models.CharField(max_length=128)
address_lineOne = models.CharField(max_length=128)
address_lineTwo = models.CharField(max_length=128)
city = models.CharField(max_length=128)
State = models.CharField(max_length=128)
zipCode = models.CharField(max_length=10)
def __unicode__(self):
return self.user.username
Solution:
first_name = request.POST.get('first_name')
user.first_name = first_name
user.save()
Thanks ejey for resolving my csrf ajax issue.
If you are intending on posting using ajax you ought to use have a view method such as:
def some_ajax_view(request):
data = request.POST.copy()
if request.is_ajax() and request.POST:
...
...
You can get more information on how to process your ajax request without having to compromise on the csrf https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax
Firstly, you didn't answer my question about the error message. This is a vital step in debugging, and it's very little use coming onto SO and asking questions without first finding the actual error and doing what you can to fix it yourself.
That said, you do have a huge obvious bug in your code. If the request is not a POST, and/or the form is not valid, what are you expecting to happen? Currently, your code just stops; so in either of those cases it will return None, which is an error: all views must return an HttpResponse. If you did look at the error message, that is probably what it would say.
You should ensure that your view at least returns an empty HttpResponse in either of those circumstances. More useful, though, would be a response that actually contains the errors from the form validation.

Resources