我试图从我的Django / Angular应用程序中的表单中获取输入数据。但问题是,当我填写表单并提交表单时,表单无法说明我的所有字段都是必需的。我不确定这是Django问题,人为错误,还是因为Angular。我认为它可能是Angular的原因是因为我的csrf_token也在渲染到页面。完全糊涂了。
视图
def login(request):
# """ -Log in the user if credentials are valid """
if request.method == "POST":
form = LoginForm(request.POST)
if form.is_valid():
cleaned_data = form.clean()
account = Account.objects.get(email=cleaned_data['email'], password=cleaned_data['password'])
if cleaned_data['token']:
token = cleaned_data['token']
invite = OrgInvite.objects.get(token=token)
org = Org.objects.get(id=invite.org_id)
if not invite:
raise Exception("Invitation token is invalid.")
if invite.used == True:
raise Exception("Invitation token has already been used.")
org_member = OrgMember.objects.get(account_id=account.id)
if org_member:
raise Exception("Account is already in team.")
else:
org.add_members(account.id, False, invite.is_admin)
invite.used = False
# add_to_welcome(org_id=org.id, account_id=account.id, inviter_id=invite.token)
else:
pass
context = {
'message': form.errors,
'next': '/app/'
}
return composeJsonResponse(200, "", context)
表格
class LoginForm(forms.Form):
email = forms.EmailField(max_length=100)
password = forms.CharField(max_length=20)
token = forms.CharField(max_length=20)
def __init__(self, *args, **kwargs):
self.cached_user = None
self.request = kwargs
kwargs.setdefault('label_suffix', '')
super(LoginForm, self).__init__(*args, **kwargs)
def clean(self):
cleaned_data = self.cleaned_data
if len(self._errors) > 0:
return cleaned_data
else:
email = cleaned_data.get('email')
password = cleaned_data.get('password')
if email is None or password is None:
messages.error(self.request, 'Please enter an email and password.')
return forms.ValidationError("Error")
else:
self.cached_user = authenticate(username=email, password=password)
if self.cached_user is None:
self._errors["password"] = self.error_class(["Password incorrect. Passwords are case sensitive."])
elif not self.cached_user.is_active:
messages.error(self.request,
'This account is inactive. Please check your inbox for our confirmation email, and '
'click the link within to activate your account.')
raise forms.ValidationError("Error")
if not cleaned_data.get('remember_me'):
self.request.session.set_expiry(0)
return cleaned_data
def get_user(self):
return self.cached_user
的login.html
<div class="account-login" id="login-view">
<div class="card card-half">
<h2 class="text-center">Welcome back!</h2>
<h4 class="text-center">Sign in to your account.</h4>
<div class="alert alert-danger" ng-if="vm.errorMessage">
{{ vm.errorMessage }}
</div>
<form class="form-horizontal" name="form" ng-submit="vm.login(vm.auth)">
{% csrf_token %}
<div class="form-group">
<label for="email" class="col-sm-3 control-label">Email</label>
<div class="col-sm-9 col-md-7">
<input type="email" id="email"
class="form-control"
placeholder="name@example.com"
ng-model="vm.auth.email"
required
hl-focus>
</div>
</div>
<div class="form-group">
<label for="password" class="col-sm-3 control-label">Password</label>
<div class="col-sm-9 col-md-7">
<input type="password" id="password" name="password"
class="form-control"
placeholder="******"
ng-model="vm.auth.password"
required minlength="6">
<div class="has-warning" ng-if="form.password.$dirty">
<div class="help-block" ng-messages="form.password.$error">
<div ng-message="minlength">Please enter at least six characters.
</div>
</div>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-3"></div>
<div class="col-sm-9 col-md-7">
<button type="submit" class="btn btn-block btn-secondary"
ng-disabled="!form.$valid || vm.submitBusy">
Sign in
<span ng-if="vm.submitBusy"><i class="fa fa-circle-o-notch fa-spin"></i></span>
</button>
</div>
</div>
</form>
</div>
</div>
<div class="col-sm-6 col-sm-offset-3">
<p>Forgot your password? Reset it
<a ui-sref="auth.reset">here</a>.</p>
<p>Trying to create a team?
<a ui-sref="auth.join.personal">Sign up</a> to get started.</p>
</div>
Angular
(function () {
'use strict';
Login.$inject = ["$log", "$anchorScroll", "$stateParams", "AccountRepo", "CommonService", "CommonEvents"];
angular
.module('app.guest')
.controller('Login', Login);
/** @ngInject */
function Login($log, $anchorScroll, $stateParams,
AccountRepo, CommonService, CommonEvents) {
var vm = this;
var next = null;
var defaultAuth = {
email: '',
password: ''
};
vm.errorMessage = null;
vm.submitBusy = false;
vm.auth = angular.copy(defaultAuth);
vm.login = login;
init();
function init() {
CommonService.broadcast(CommonEvents.viewReady);
next = $stateParams.next;
}
function login(model) {
vm.submitBusy = true;
vm.errorMessage = null;
AccountRepo.login(model).then(
function (data) {
// CommonService.hardRedirect(next || '/app');
console.log(data)
},
function (data) {
vm.submitBusy = false;
vm.errorMessage = data;
$anchorScroll('login-view');
});
}
}
})();
(function () {
'use strict';
AccountRepo.$inject = ["$q", "$log", "AbstractRepo"];
angular
.module('app.repo')
.factory('AccountRepo', AccountRepo);
function AccountRepo($q, $log, AbstractRepo) {
return {
accept: accept,
invite: invite,
join: join,
login: login,
save: save
};
/**
* Create a new account with a new team.
* @param model:
* @returns {*}
*/
function join(model) {
return AbstractRepo.post('accounts/signup', model, false)
.then(genericSuccess, genericError);
}
/**
* Authenticate an account.
* @param model:
* @returns {*}
*/
function login(model) {
return AbstractRepo.post('accounts/login/', model, false)
.then(genericSuccess, genericError);
}
angular
.module('app.repo')
.factory('AbstractRepo', AbstractRepo);
/** ngInject */
function AbstractRepo($log, $http, $q, Config) {
return {
get: get,
post: post,
put: put,
genericSuccess: genericSuccess,
genericError: genericError
};
function get(uri, data, isApi) {
return httpRequest('GET', uri, data, isApi);
}
function post(uri, data, isApi) {
return httpRequest('POST', uri, data, isApi);
}
function put(uri, data, isApi) {
return httpRequest('PUT', uri, data, isApi);
}
function httpRequest(method, uri, data, isApi) {
isApi = angular.isDefined(isApi) ? isApi : true;
var deferred = $q.defer();
var promise = $http({
method: method,
url: (isApi ? Config.api_path : '/') + uri,
data: data || {},
timeout: deferred.promise
}).catch(function (response) {
$log.error(response);
return $q.reject(response);
}).finally(function () {
promise.abort = angular.noop;
deferred = null;
promise = null;
});
// Abort the underlying request.
promise.abort = function () {
deferred.resolve();
};
return promise;
}
function genericSuccess(response) {
return response.data;
}
function genericError(response) {
var reason = "Oops, something went wrong. That's our bad.";
if (response.status < 500 && response.data.message) {
reason = response.data.message;
}
return $q.reject(reason);
}
}
将request.body放入LoginForm后的回溯。当我的视图遇到form.is_valid()方法时会发生错误。
ERROR 2016-04-19 10:57:38,949 base.py handle_uncaught_exception 284 Internal Server Error: /accounts/login/
Traceback (most recent call last):
File "/usr/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 149, in get_response
response = self.process_exception_by_middleware(e, request)
File "/usr/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 147, in get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/timothybaney/Django_Projects/human_link/backend/account/views.py", line 70, in login
if form.is_valid():
File "/usr/local/lib/python2.7/site-packages/django/forms/forms.py", line 161, in is_valid
return self.is_bound and not self.errors
File "/usr/local/lib/python2.7/site-packages/django/forms/forms.py", line 153, in errors
self.full_clean()
File "/usr/local/lib/python2.7/site-packages/django/forms/forms.py", line 362, in full_clean
self._clean_fields()
File "/usr/local/lib/python2.7/site-packages/django/forms/forms.py", line 374, in _clean_fields
value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
File "/usr/local/lib/python2.7/site-packages/django/forms/widgets.py", line 231, in value_from_datadict
return data.get(name)
AttributeError: 'str' object has no attribute 'get'
答案 0 :(得分:0)
我感谢大家的帮助!我终于找到了问题所在。我觉得很奇怪回答我自己的问题,但是为了防止其他人遇到同样的问题,我将包含其他堆栈溢出文章的链接,这些文章帮助我解决了问题。基本上,由于Angular使用AJAX调用,我无法使用request.POST。我不得不使用request.body。由于AJAX帖子数据只是json,我还必须将request.body转换为查询字典,以便在我的登录表单中使用。
# Converts AJAX JSON into query dictionary for the view to process.
def requestPost(request):
querystring = urllib.urlencode(ast.literal_eval(request.body))
postdata = QueryDict(query_string=querystring)
return postdata
def login(request):
if request.is_ajax():
if request.method == "POST":
form = LoginForm(requestPost(request))
if form.is_valid():
cleaned_data = form.cleaned_data
if len(form.errors) > 0:
return cleaned_data
else:
email = cleaned_data.get('email')
password = cleaned_data.get('password')
if email is None or password is None:
messages.error(form.request, 'Please enter an email and password.')
return form.ValidationError("Error")
else:
form.cached_user = authenticate(username=email, password=password)
if not form.cached_user:
x = True
else:
x = False
if form.cached_user is None:
form.errors["password"] = form.error_class(["Password incorrect. Passwords are case sensitive."])
elif not form.cached_user.is_active:
messages.error(form.request,
'This account is inactive. Please check your inbox for our confirmation email, and '
'click the link within to activate your account.')
raise form.ValidationError("Error")
return cleaned_data
account = Account.objects.get(email=cleaned_data['email'], password=cleaned_data['password'])
if cleaned_data['token']:
token = cleaned_data['token']
invite = OrgInvite.objects.get(token=token)
org = Org.objects.get(id=invite.org_id)
if not invite:
raise Exception("Invitation token is invalid.")
if invite.used == True:
raise Exception("Invitation token has already been used.")
org_member = OrgMember.objects.get(account_id=account.id)
if org_member:
raise Exception("Account is already in team.")
else:
org.add_members(account.id, False, invite.is_admin)
invite.used = False
# add_to_welcome(org_id=org.id, account_id=account.id, inviter_id=invite.token)
else:
pass
context = {
'message': form.errors,
'next': '/app/'
}
return composeJsonResponse(200, "", context)
相关的Stack Overflow问题。