1. Дмитрий

    06.07.2012

    0 ↑
    0 ↓
    Здравствуйте.

    Создал форму:
    from django import forms
    from auth.models import Member
    from hashlib import sha1

    class LoginForm(forms.Form):
    email = forms.EmailField()
    password = forms.CharField()

    def __init__(self, *args, **kwargs):
    super(LoginForm, self).__init__(*args, **kwargs)
    self.email = kwargs.pop('email')
    self.password = kwargs.pop('password')

    def clean(self):
    password = sha1(self.password).hexdigest()
    member = Member.objects(
    email=self.email,
    password=password
    ).limit(1)
    if len(member) != 1:
    raise forms.ValidationError("Your sign in credentials are incorrect.")
    return self.cleaned_data
    Возвращает ошибку:
    pop(): dictionary is empty

    Указывая на 11 строку:
    self.email = kwargs.pop('email')
  2. Роман

    06.07.2012

    0 ↑
    0 ↓
    Дмитрий, ну а Вы в форму передавали параметр "email"?
  3. Дмитрий

    06.07.2012

    0 ↑
    0 ↓
    Роман, получается, что надо сначала проверить на существование?
  4. Роман

    06.07.2012

    1 ↑
    0 ↓
    Получайте значение email и password из словаря: self.cleaned_data.get('xxx'),
    где xxx - имя необходимого поля.
  5. Роман

    06.07.2012

    0 ↑
    0 ↓
    Дмитрий, что Вы вообще хотите сделать?
    Авторизацию?
    Если да, то Ваш путь неправильный.
  6. Дмитрий

    06.07.2012

    0 ↑
    0 ↓
    Огромное спасибо.
    Вот сейчас как выглядит код:
    from django import forms
    from auth.models import Member
    from hashlib import sha1

    class LoginForm(forms.Form):
    email = forms.EmailField(required=True)
    password = forms.CharField(required=True)

    def clean(self):
    email = self.cleaned_data.get('email')
    password = self.cleaned_data.get('password')
    password = sha1(password).hexdigest()
    member = Member.objects(
    email=self.email,
    password=password
    ).limit(1)
    if len(member) != 1:
    raise forms.ValidationError("Your sign in credentials are incorrect.")
    return self.cleaned_data
    И проблема в том, что валидатор пропускает пустые инпуты и не валедирует адрес эл. почты. Хотя у меня написано:
    required=True
    Почему так получается? Наверное из-за того, что метод clean срабатывает раньше, чем валидатор формы? Какой мне метод тогда лучше всего использовать? Есть ли метод, который выполняется в самом конце, как деструктор?
  7. Дмитрий

    06.07.2012

    0 ↑
    0 ↓
    Да, я хочу сделать авторизацию. А почему не верный ход? Меня стандартные средства авторизации не устраивают.
  8. Роман

    06.07.2012

    1 ↑
    0 ↓
    Дмитрий, вот это:
    member = Member.objects(email=self.email, 
    password=password
    ).limit(1)
    можно вынести в backend.
    Очень удобно в этом случае добавлять/изменять/удалять источники для авторизации.
    Попробуйте так:
    super(LoginForm, self).clean()
    email = self.cleaned_data.get('email')
    password = self.cleaned_data.get('password')
    password = sha1(password).hexdigest()
    member = Member.objects(
    email=self.email,
    password=password
    ).limit(1)
    if len(member) != 1:
    raise forms.ValidationError("Your sign in credentials are incorrect.")
    return self.cleaned_data
  9. Роман

    06.07.2012

    0 ↑
    0 ↓
    def clean(self):
    ... разместить здесь, что было выше
  10. Роман

    06.07.2012

    1 ↑
    0 ↓
    Можете сделать еще так:
    if email and password:
    # тут проверяем, почту и пароль.
    а можно так:
    try:
    member = Member.objects(
    email=self.email,
    password=password
    )
    except Member.DoesNotExist:
    raise forms.ValidationError("Your sign in credentials are incorrect.")
    Если будет пустая почта или пароль, то запись в БД будет отсутствовать, сработает ексепшн.
  11. Дмитрий

    06.07.2012

    0 ↑
    0 ↓
    А это надо было дописать в метод clean?
    def clean(self):
    super(LoginForm, self).clean()
    password = self.cleaned_data.get('password')
    ....
    Все равно
    sha1() argument 1 must be string or read-only buffer, not None
  12. Роман

    06.07.2012

    0 ↑
    0 ↓
    Да, это нужно было написать в метод clean().
    Дмитрий, а Вы уверены, что поле "password" не пустое?
    Проверьте это.
  13. Дмитрий

    06.07.2012

    0 ↑
    0 ↓
    Наоборот, я уверен, что оно пустое :) Просто сначала идет моя проверка и только после этого идет системная проверка. А мне надо, чтобы сначало проверило на required и только после этого запустило мою проверку.
  14. Дмитрий

    06.07.2012

    0 ↑
    0 ↓
    Я написал, как вы показали:
    def clean(self):
    super(LoginForm, self).clean()
    email = self.cleaned_data.get('email')
    password = self.cleaned_data.get('password')
    if email and password:
    password = sha1(password).hexdigest()
    member = Member.objects(
    email=self.email,
    password=password
    ).limit(1)
    if len(member) != 1:
    raise forms.ValidationError("Your sign in credentials are incorrect.")
    return self.cleaned_data
    Теперь ошибки нет, но если мы отправляем пустые поля, то ошибка не выводится, что это поле обязательно к заполнению.
  15. Во-первых,

    member = Member.objects(...).limit(1)
    if len(member) != 1:
        raise
    

    Так не надо, надо так:

    if not Member.objects.filter(...).exists()
       raise
    

    или, если результат надо использовать где-то еще

    try:
        member = Member.objects.get(...)
    except Member.DoesNotExist:
        raise
    

    Во-вторых, пароли в базе - legacy? Если нет, лучше использовать что-то посерьезнее SHA1 без соли.

    В-третьих, аутентификацией должен заниматься соответствующий backend, посмотрите, как сделано в джанговской форме входа.

    В-четвертых, как Вы создаете объект формы и проверку валидности? И как выводите в шаблоне?

  16. Дмитрий

    07.07.2012

    0 ↑
    0 ↓
    Так, давайте я покажу, что я уже смог натворить:
    models.py
    from mongoengine import *
    from hashlib import md5

    class Member(DynamicDocument):
    first_name = StringField(required=True)
    last_name = StringField(required=True)
    email = EmailField(required=True, unique=True)
    password = StringField(required=True)

    def auth(self, email, password):
    if email == None or password == None:
    return False
    password = md5(password).hexdigest()
    try:
    member = Member.objects(email=email, password=password).limit(1)
    return True
    except Member.DoesNotExist:
    return False
    views.py
    from django.shortcuts import render_to_response
    from auth.forms import LoginForm
    from django.views.decorators.csrf import csrf_exempt

    @csrf_exempt
    def login(request):
    data = {}
    if request.method == 'POST':
    form = LoginForm(request.POST)
    if form.is_valid():
    data['success'] = "All is ok"
    else:
    form = LoginForm()
    else:
    form = LoginForm()
    data['form'] = form
    return render_to_response('auth/login.html', data)

    login.html
    <!DOCTYPE HTML>
    <html lang="en-US">
    <head>
    <meta charset="UTF-8">
    <title></title>
    </head>
    <body>
    {% if success %}
    {{ success }}
    {% endif %}
    {% if form.errors %}
    <div id="form-error">
    <ul>
    {% for field in form %}
    <li>{{ field.errors|striptags }}</li>
    {% endfor %}
    </ul>
    </div>
    {% endif %}
    <form action="." method="post">{% csrf_token %}
    {{ form.non_field_errors }}
    {{ form.as_p }}
    <input type="submit" value="Submit" />
    </form>
    </body>
    </html>
    forms.py
    from django import forms
    from auth.models import Member

    class LoginForm(forms.Form):
    email = forms.EmailField(required=True)
    password = forms.CharField(required=True)

    def clean(self):
    super(LoginForm, self).clean()
    email = self.cleaned_data.get('email')
    password = self.cleaned_data.get('password')
    if not Member.auth(email, password):
    raise forms.ValidationError("Your sign in credentials are incorrect.")
    return self.cleaned_data
    Я слепой, не вижу ошибки. Я где-то намудрил, что в Members.auth не передается логин и пароль
  17. Менять SHA1 без соли на MD5 без соли сейчас смысла практически не имеет. Что Вам мешает использовать встроенные в Django механизмы, вроде pbkdf2?

    Почему не используете бэкенд авторизации, как Вам советовали выше?

    Как определяете, что в auth не приходят логин и пароль?

    Зачем вызываете дополнительно clean() родителя у себя? Это не нужно.

    Зачем, если форма невалидная, Вы создаете ее заново?

    Ну и так далее. Вам надо понять, что Вы хотите сделать. Возможно, на бумажке нарисовать. И только потом код писать. И тесты.

    А не постить сюда колбасу за колбасой "от балды" - в чистом виде FDD получается.

Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.