Django login authentication not working - django-forms

I am trying to use the generic login view provided by Django. i want the registration and login form on the same page. Here is my urls.py
from django.conf.urls import patterns, include, url
from myApp.forms import UsersForm
urlpatterns = patterns('',
url(r'^$', 'django.contrib.auth.views.login', {'template_name': 'templates/login.html', 'authentication_form':UsersForm}),
)
and this is my login.html
<html>
<body>
<form method="post" action="">{% csrf_token %}
{{ authentication_form.first_name }} {{authentication_form.last_name }} <br>
{{ authentication_form.username }} {{ authentication_form.password }} <br>
<input type="submit" value="Register"/>
</form>
{% for field, error in form.errors.items %}
{% if forloop.counter == 1 %}
{{ error | striptags }}
{% endif %}
{% endfor %}
<form method="post" action="{% url 'django.contrib.auth.views.login' %}">{% csrf_token%}
{{authentication_form.username.label_tag}}
{{authentication_form.username}}
{{authentication_form.password.label_tag}}
{{authentication_form.password}}
<input type="submit" value="login" />
<input type="hidden" name="next" value="{{ next }}" />
</form>
</body>
</html>
When I run the server and go to 127.0.0.1, only the login and register Buttons show up, the actual fields do not (I can't type anything in anywhere on the page, there are just two buttons, one which says 'login' and another which says 'register'. There is just a blank white space where the actual fields should be. How come the box for username, password, first name and last name aren't showing up?
EDIT: when I change authentication_form.username to just form.username, it gives a template error saying
'WSGIRequest' object has no attribute 'get'
and the traceback to this is
Traceback:
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py" in get_response
140. response = response.render()
File "/usr/local/lib/python2.7/dist-packages/django/template/response.py" in render
105. self.content = self.rendered_content
File "/usr/local/lib/python2.7/dist-packages/django/template/response.py" in rendered_content
82. content = template.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render
140. return self._render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in _render
134. return self.nodelist.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render
830. bit = self.render_node(node, context)
File "/usr/local/lib/python2.7/dist-packages/django/template/debug.py" in render_node
74. return node.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/debug.py" in render
87. output = force_text(output)
File "/usr/local/lib/python2.7/dist-packages/django/utils/encoding.py" in force_text
99. s = s.__unicode__()
File "/usr/local/lib/python2.7/dist-packages/django/forms/forms.py" in __str__
411. return self.as_widget()
File "/usr/local/lib/python2.7/dist-packages/django/forms/forms.py" in as_widget
458. return widget.render(name, self.value(), attrs=attrs)
File "/usr/local/lib/python2.7/dist-packages/django/forms/forms.py" in value
494. self.data, self.form.initial.get(self.name, self.field.initial)
File "/usr/local/lib/python2.7/dist-packages/django/forms/forms.py" in _data
480. return self.field.widget.value_from_datadict(self.form.data, self.form.files, self.html_name)
File "/usr/local/lib/python2.7/dist-packages/django/forms/widgets.py" in value_from_datadict
209. return data.get(name, None)
Exception Type: AttributeError at /
Exception Value: 'WSGIRequest' object has no attribute 'get'
My generic login view is just this
def login(request, template_name='registration/login.html',
redirect_field_name=REDIRECT_FIELD_NAME,
authentication_form=AuthenticationForm,
current_app=None, extra_context=None):
"""
Displays the login form and handles the login action.
"""
redirect_to = request.REQUEST.get(redirect_field_name, '')
if request.method == "POST":
form = authentication_form(data=request.POST)
if form.is_valid():
# Ensure the user-originating redirection url is safe.
if not is_safe_url(url=redirect_to, host=request.get_host()):
redirect_to = resolve_url(settings.LOGIN_REDIRECT_URL)
# Okay, security check complete. Log the user in.
auth_login(request, form.get_user())
if request.session.test_cookie_worked():
request.session.delete_test_cookie()
return HttpResponseRedirect(redirect_to)
else:
form = authentication_form(request)
request.session.set_test_cookie()
current_site = get_current_site(request)
context = {
'form': form,
redirect_field_name: redirect_to,
'site': current_site,
'site_name': current_site.name,
}
if extra_context is not None:
context.update(extra_context)
return TemplateResponse(request, template_name, context,
current_app=current_app)
I didn't make any changes to template_name (although I did specify template_name in my urls.py which can be seen above) or current_app. My form class in forms.py is this
class UsersForm(forms.ModelForm):
class Meta:
model = Users
widgets = {'password':forms.PasswordInput()}
def __init__(self, *args, **kwargs):
super( UsersForm, self ).__init__(*args, **kwargs)
self.fields[ 'first_name' ].widget.attrs[ 'placeholder' ]="First Name"
self.fields[ 'last_name' ].widget.attrs[ 'placeholder' ]="Last Name"
self.fields[ 'username' ].widget.attrs[ 'placeholder' ]="Username"
self.fields[ 'password' ].widget.attrs[ 'placeholder' ]="Password"
self.fields['first_name'].error_messages = {'required': 'Please enter your First Name.', 'max_length': 'Your First Name must be shorter than 50 characters.'}
self.fields['last_name'].error_messages = {'required': 'Please enter your Last Name.', 'max_length': 'Your last Name must be shorter than 50 characters.'}
self.fields['password'].error_messages = {'required': 'Please enter a Password.', 'max_length': 'Your Password must be shorter than 50 characters.', 'invalid': 'Your Password can only contain letters, numbers, underscores, and hyphens.'}
self.fields['username'].error_messages = {'required': 'Please enter a Username.', 'max_length': 'Your Username must be shorter than 50 characters.', 'invalid': 'Your Username can only contain letters, numbers, underscores, and hyphens.',}
def clean_date_of_birth_month(self):
data = self.cleaned_data.get('date_of_birth_month')
if data == 'Month':
raise forms.ValidationError('Please enter a correct Month for your date of birth.')
return data
def clean_date_of_birth_day(self):
data = self.cleaned_data.get('date_of_birth_day')
if data == 'Day':
raise forms.ValidationError('Please enter a correct Day for your date of birth.')
return data
def clean_date_of_birth_year(self):
data = self.cleaned_data.get('date_of_birth_year')
if data == 'Year':
raise forms.ValidationError('Please enter a correct Year for your date of birth.')
return data
It is a form created from an existing model, which is this
class Users(models.Model):
months = (
('Month','Month'), ('January', 'January'), ('February','February'), ('March','March'), ('April','April'), ('May','May'), ('June','June'),
('July','July'), ('August','August'), ('September','September'), ('October','October'), ('November','November'), ('December','December'),
)
days = (
('Day', 'Day'), ('1','1'), ('2','2'), ('3','3'), ('4','4'), ('5','5'), ('6','6'), ('7','7'), ('8','8'), ('9','9'), ('10','10'), ('11','11'),
('12','12'), ('13','13'), ('14','14'), ('15','15'), ('16','16'), ('17','17'), ('18','18'), ('19','19'), ('20','20'), ('21','21'), ('22','22'),
('23','23'), ('24','24'), ('25','25'), ('26','26'), ('27','27'), ('28','28'), ('29','29'), ('30','30'),('31','31'),
)
years = (
('Year','Year'), ('2013','2013'), ('2012','2012'), ('2011','2011'), ('2010','2010'), ('2009','2009'), ('2008','2008'),
)
alpha_field = RegexValidator(regex=r'^[a-zA-Z]+$', message='Name can only contain letters.')
user_id = models.AutoField(unique=True, primary_key=True)
first_name = models.CharField(max_length=50, validators=[alpha_field])
last_name = models.CharField(max_length=50, validators=[alpha_field])
username = models.SlugField(max_length=50, unique=True, error_messages={'unique': u'A user with that Username already exists. Please choose a different Username.'})
password = models.SlugField(max_length=50)
date_of_birth_month = models.CharField(verbose_name='', max_length=9, choices=months, default='Month')
date_of_birth_day = models.CharField(verbose_name='', max_length=3, choices=days, default='Day')
date_of_birth_year = models.CharField(verbose_name='', max_length=4, choices=years, default='Year')

Try with
{{form.username}}
because generic view names it that way:
form = authentication_form(request)

Related

Auto filling a form's foreign key

So, i have been having problems filling in the user in a form. My strategy has been validating the form, creating an object, passing the foreign key and the other fields with .cleaned_data and saving the object.
More specifically, I basically want to create a "workout" object in the database, adding a name and a description from the form and autofilling the created_by_user field.
views.py
#login_required(login_url='login')
def workouts(request, user_id):
context = {}
if request.method == 'POST':
form = WorkoutForm(request.POST)
if form.is_valid():
name = form.cleaned_data['name']
description = form.cleaned_data['description']
Workout.objects.create(
created_by_user=request.user, name=name, description=description)
context = {'name': name, 'description': description}
return render(request, 'Trainmate/fill_workout_with_sets.html', context)
else:
form = WorkoutForm()
workout_programs = Workout.objects.all()
user_workouts = workout_programs.filter(created_by_user=user_id)
context = {'user_workouts': user_workouts, 'form': form}
return render(request, 'Trainmate/workouts.html', context)
models.py (I am just adding the workout model)
class Workout(models.Model):
name = models.CharField(max_length=150, null=True)
created_by_user = models.ForeignKey(User, null=True, on_delete=models.RESTRICT)
description = models.TextField(max_length=1000, null=True)
def __str__(self):
return self.name
forms.py
class WorkoutForm(forms.ModelForm):
class Meta:
model = Workout
fields = ['name', 'description', 'created_by_user']
my template
{% extends 'Trainmate/main.html' %}
{% block content %}
<h1>My Workouts</h1>
<div>
{% for workout in user_workouts %}
{{ workout.name }}<br>
{% endfor %}
</div>
<h1>Create new Workout</h1>
<form method="POST" action="">
{% csrf_token %}
{{ form.name }}
{{ form.description }}
<input type="submit" value="Create Workout">
</form>
You can remove 'created_by_user' from the fields list in your form as you do not need it to display or validating. Then render the form just with {{ form }}.
You can use save() method since you use a ModelForm. Change your view accordignly:
#login_required(login_url='login')
def workouts(request, user_id):
context = {}
if request.method == 'POST':
form = WorkoutForm(request.POST)
if form.is_valid():
workout = form.save(commit=False)
workout.created_by_user = request.user
workout.save()
context = {'name': name, 'description': description}
return render(request, 'Trainmate/fill_workout_with_sets.html', context)
else:
form = WorkoutForm()
workout_programs = Workout.objects.all()
user_workouts = workout_programs.filter(created_by_user=user_id)
context = {'user_workouts': user_workouts, 'form': form}
return render(request, 'Trainmate/workouts.html', context)

Select a valid choice. <some choice> is not one of the available choices

I am trying to build a Form which will show a choice field with options. Now these options changes for different kind of user. I am able to set the values in the choice field from view. The problem is when I click on "Submit" all the fields become empty and get the error like "Select a valid choice. 2 is not one of the available choices."
Logic to find the correct list of companies to show in the choice field.
def get_my_companies(user):
if user.profile.company.is_customer:
return (user.profile_set.company.id,user.profile_set.company.name)
elif user.is_superuser:
companies = Company.objects.filter(is_customer=True)
list_of_companies = [(c.id, c.name) for c in companies]
return list_of_companies
else:
list_of_groups = list(user.groups.values_list('name',flat = True))
list_of_companies = []
# ... some more logic to find appropriate list of companies for each such user
return list_of_companies
The logic is working correctly and the values are getting populated on the page load. Only problem occurs when I submit the form.
views.py
def home(request):
my_companies = get_my_companies(request.user)
myForm = device_readings_form()
myForm.fields['company'].choices = my_companies
if request.method == 'POST':
myForm = device_readings_form(request.POST)
is_historical = True
if myForm.is_valid():
cd = myForm.cleaned_data
company = cd.get('company')
#device = cd.get('device')
date_from = cd.get('date_from')
date_to = cd.get('date_to')
print(date_from)
print(date_to)
# .... some more stuff to work. Then I return the render using template
context = {
'readings': data,
'columns' : df.columns,
'range' : {
'from' : datetime.datetime.now().strftime('%Y-%m-%d')+ ' 00:00:00',
'to': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
},
'is_historical' : is_historical,
'show_chart' : show_chart,
'form' : myForm
}
return render(request,'portal/home.html',context)
forms.py
class device_readings_form(forms.Form):
initial_from_date = datetime.date.today()
initial_to_date = initial_from_date + datetime.timedelta(days=1)
date_from = forms.DateField(initial=initial_from_date)
date_to = forms.DateField(initial=initial_to_date)
company = forms.ChoiceField()
portal/home.html
{% block sidebar %}
<div class="col-md-4">
<div class="content-section">
<p class='text-muted'> <h5>Get Historical Readings</h5>
<form method="POST" action="{% url 'portal-home' %}">
{% csrf_token %}
{{form|crispy}}
<button type="submit">Submit</button>
</form>
</p>
</div>
</div>
{% endblock sidebar %}
The problem is faced only in case of ChoiceField. If I remove the ChoiceField and keep only remaining two DateFields then form gets properly submitted and I am able to read the form values in the view.
Can you guys please point me in right direction what I am doing wrong?
I would like to get the form submitted properly and get the form values in the view to process.
SOLVED!!!
The solution is:
One need to set the choices in the form instance.
Modified the code like below:
forms.py
class device_readings_form(forms.Form):
company = forms.ChoiceField()
devices = forms.ChoiceField()
initial_from_date = datetime.date.today()
initial_to_date = initial_from_date + datetime.timedelta(days=1)
date_from = forms.DateField(initial=initial_from_date)
date_to = forms.DateField(initial=initial_to_date)
def __init__(self, companies, devices, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['company'].choices = companies
self.fields['devices'].choices = devices
views.py
def home(request):
my_companies = get_my_companies(request.user)
my_devices, total_list = get_available_devices(my_companies)
is_historical = False
show_chart = False
myForm = device_readings_form(my_companies, total_list)
#myForm.fields['company'].choices = my_companies
if request.method == 'POST':
myForm = device_readings_form(my_companies, total_list, request.POST or None)
is_historical = True
if myForm.is_valid():
cd = myForm.cleaned_data
company = cd.get('company')
device = cd.get('devices')
date_from = cd.get('date_from')
date_to = cd.get('date_to')
print(company)
print(device)
print(date_from)
print(date_to)

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'),

Ajax POST Form to Django Data Issue

been frustrated with this for a couple days and was wondering if anyone could help. I'm new to Ajax and trying to post data from a login form in order to login to Django (Django Userena). However, when I try to post the data, alert() shows me the error in data as [object object]. I can't even see the network error code because the POST gets canceled before it can run.
Is there a way to just send the data and not the entire JSON array that I think its sending, or do I need to parse it out on the Django view backend. What is the best way to accomplish this code wise? Thank you very much!
Below is the relevant code:
Ajax Code:
$('#login').submit(function(){
$.ajax({
url: 'http://127.0.0.1:8000/accounts/signin/',
type: 'POST',
data: {
csrfmiddlewaretoken: '{{csrf_token}}',
identification: $("#id_identification").val(),
password: $("#id_password").val(),
},
success: function() {
alert('Test');
$('#datadisplay').append("<h2>It worked</h2>");
},
error: function(errorThrown){
console.log(errorThrown);
alert('Error');
alert(errorThrown);
}
});
});
Form on Index.html
<form name="login" id="login" action="">
<fieldset>
<label for="id_identification">Email or username</label>
<input class="required" id="id_identification" maxlength="75" name="identification" type="text" />
<label for="id_password">Password</label>
<input class="required" id="id_password" name="password" type="password" />
<input type="submit" name="submit" class="loginbutton" value="Login" />
</fieldset>
</form>
views.py from Django-Userena
#secure_required
def signin(request, auth_form=AuthenticationForm,
template_name='userena/signin_form.html',
redirect_field_name=REDIRECT_FIELD_NAME,
redirect_signin_function=signin_redirect, extra_context=None):
"""
Signin using email or username with password.
Signs a user in by combining email/username with password. If the
combination is correct and the user :func:`is_active` the
:func:`redirect_signin_function` is called with the arguments
``REDIRECT_FIELD_NAME`` and an instance of the :class:`User` who is is
trying the login. The returned value of the function will be the URL that
is redirected to.
A user can also select to be remembered for ``USERENA_REMEMBER_DAYS``.
:param auth_form:
Form to use for signing the user in. Defaults to the
:class:`AuthenticationForm` supplied by userena.
:param template_name:
String defining the name of the template to use. Defaults to
``userena/signin_form.html``.
:param redirect_field_name:
Form field name which contains the value for a redirect to the
succeeding page. Defaults to ``next`` and is set in
``REDIRECT_FIELD_NAME`` setting.
:param redirect_signin_function:
Function which handles the redirect. This functions gets the value of
``REDIRECT_FIELD_NAME`` and the :class:`User` who has logged in. It
must return a string which specifies the URI to redirect to.
:param extra_context:
A dictionary containing extra variables that should be passed to the
rendered template. The ``form`` key is always the ``auth_form``.
**Context**
``form``
Form used for authentication supplied by ``auth_form``.
"""
form = auth_form()
if request.method == 'POST':
form = auth_form(request.POST, request.FILES)
if form.is_valid():
#identification, password, remember_me = (form.cleaned_data['identification'],
#form.cleaned_data['password'],
#form.cleaned_data['remember_me'])
identification, password = (form.cleaned_data['identification'], form.cleaned_data['password'])
user = authenticate(identification=identification,
password=password)
if user.is_active:
login(request, user)
if remember_me:
request.session.set_expiry(userena_settings.USERENA_REMEMBER_ME_DAYS[1] * 86400)
else: request.session.set_expiry(0)
if userena_settings.USERENA_USE_MESSAGES:
messages.success(request, _('You have been signed in.'),
fail_silently=True)
# Whereto now?
redirect_to = redirect_signin_function(
request.REQUEST.get(redirect_field_name), user)
return HttpResponseRedirect(redirect_to)
else:
return redirect(reverse('userena_disabled',
kwargs={'username': user.username}))
if not extra_context: extra_context = dict()
extra_context.update({
'form': form,
'next': request.REQUEST.get(redirect_field_name),
})
return ExtraContextTemplateView.as_view(template_name=template_name,
extra_context=extra_context)(request)
AuthenticationForm
class AuthenticationForm(forms.Form):
"""
A custom form where the identification can be a e-mail address or username.
"""
identification = identification_field_factory(_(u"Email or username"),
_(u"Either supply us with your email or username."))
password = forms.CharField(label=_("Password"),
widget=forms.PasswordInput(attrs=attrs_dict, render_value=False))
remember_me = forms.BooleanField(widget=forms.CheckboxInput(),
required=False,
label=_(u'Remember me for %(days)s') % {'days': _(userena_settings.USERENA_REMEMBER_ME_DAYS[0])})
def __init__(self, *args, **kwargs):
""" A custom init because we need to change the label if no usernames is used """
super(AuthenticationForm, self).__init__(*args, **kwargs)
# Dirty hack, somehow the label doesn't get translated without declaring
# it again here.
self.fields['remember_me'].label = _(u'Remember me for %(days)s') % {'days': _(userena_settings.USERENA_REMEMBER_ME_DAYS[0])}
if userena_settings.USERENA_WITHOUT_USERNAMES:
self.fields['identification'] = identification_field_factory(_(u"Email"),
_(u"Please supply your email."))
def clean(self):
"""
Checks for the identification and password.
If the combination can't be found will raise an invalid sign in error.
"""
identification = self.cleaned_data.get('identification')
password = self.cleaned_data.get('password')
if identification and password:
user = authenticate(identification=identification, password=password)
if user is None:
raise forms.ValidationError(_(u"Please enter a correct username or email and password. Note that both fields are case-sensitive."))
return self.cleaned_data
These are the errors (not all and I think there are more) I see when I test your codes:
how can you login if you didn't use your AuthenticationForm() in your template. You form codes in the template is different.
you didn't put method="POST" in your form which result on GET response instead of POST.
you forgot to put {% csrf_token %} in your template form
In your views.py, user = authenticate(identification=identification, password=password) must be user = authenticate(username=identification, password=password)
In your forms.py, user = authenticate(identification=identification, password=password) must be user = authenticate(username=identification, password=password)
Your ajax codes has no effect that's why you can't get the error thrown. I think your missing something in your ajax.
To get the details of the error thrown:
error: function(ts){
//console.log(errorThrown);
//alert('Error');
alert(ts.responseText);
}
your ajax data must have '':
data: {
'csrfmiddlewaretoken': '{{csrf_token}}',
'identification': $("#id_identification").val(),
'password': $("#id_password").val(),
},
You don't have to elaborate your url like this one
url: 'http://127.0.0.1:8000/accounts/signin/',
It will result to
"http://127.0.0.1:8000/http://127.0.0.1:8000/accounts/signin/"
It must be
url: '/accounts/signin/',
and don't also forget to put
contentType: "application/json;charset=utf-8",
dataType: "json",
There are more errors and until now I can't successfully login.

Getting ModelForm to insert hidden field for id (preventing duplicate instance on save)

I'm trying to build a simple CUD (Create/Update/Delete) view with a ModelForm, but on save I'm getting a duplicate record:
ModelForm:
class formFacetAnswer(forms.ModelForm):
class Meta:
model = models.FacetAnswer
exclude = ('who')
View:
def xxx_test1(request):
if request.method == 'POST':
form = formFacetAnswer(request.POST)
if form.is_valid():
answer = form.save(commit=False)
answer.who = request.user
answer.save()
return HttpResponseRedirect('/')
else:
a_id = request.GET.get('answer')
if a_id:
a_id=int(a_id)
answer = models.FacetAnswer.objects.get(id=a_id)
form = formFacetAnswer(instance=answer)
else:
form = formFacetAnswer()
return render_to_response('facet_answer.html', dict(form=form), context_instance=RequestContext(request))
Template:
{% extends 'head-plain.html' %}
{% block content %}
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
{% endblock %}
The formFacetAnswer(instance=answer) does not insert a hidden field with the answer ID, so at save time it creates a new one. What's the best pattern to use for this need, under Django 1.3?
Currently you are only passing the instance on GET. If you want to update an existing record on save then you should pass the instance on POST as well.
The "obvious" way when updating ModelForms seems to be having the identifier to the instance of the object in the url.
urls.py:
url(r'^answer/(\d+)$', 'app.views.xxx_test1', name='editAnswer'),
url(r'^answer/$', 'app.views.xxx_test1', name='newAnswer '),
View:
def xxx_test1(request, a_id=None):
if request.method == 'POST':
if a_id:
answer = models.FacetAnswer.objects.get(id=a_id)
form = formFacetAnswer(request.POST, instance=answer)
else:
form = formFacetAnswer(request.POST)
if form.is_valid():
answer = form.save(commit=False)
answer.who = request.user
answer.save()
return HttpResponseRedirect('/')
else:
if a_id:
answer = models.FacetAnswer.objects.get(id=a_id)
form = formFacetAnswer(instance=answer)
else:
form = formFacetAnswer()
return render_to_response('facet_answer.html', dict(form=form), context_instance=RequestContext(request))

Resources