@maestro07

Как сделать регистрацию через активацию django?

views.py

def registration(request):
    template = "main/registration.html"
    params = dict()
    if request.method == "POST":
        email = request.POST.get("email", "").lower()
        password = request.POST.get("password", "")
        password2 = request.POST.get("password2", "")

        try:
            validate_email(email)
        except Exception as error:
            return render(request, template, params)        

        try:
            len(password) >= 5
        except Exception as error:
            messages.add_message(request, messages.ERROR, PASSWORD_ERROR)
            return render(request, template, params)        

        if password != password2:
           messages.add_message(request, messages.ERROR, DIFFERENT_PASSWORD)

        if User.objects.filter(username=email, is_active=True).exists():
            messages.add_message(request, messages.ERROR, EXIST_USER)
            return render(request, template, params)

        new_user = User.objects.create_user(username=email, password=password)
        activation_key = Activation.objects.generate(user=new_user)

        messages.add_message(request, messages.ERROR, SUCCESS)
        send_mail('activation JustSolve.kz', "hello world", settings.EMAIL_HOST_USER, ['knursultana@gmail.com'])
        # TODO: add celery
        # TODO: send verification email
    return render(request, template, params)


settings.py

EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_USER = 'myemail@gmail.com'
EMAIL_HOST_PASSWORD = 'mypassword'
EMAIL_PORT = 587
EMAIL_USE_TLS = True


models.py

class ActivationManager(models.Manager):

    def generate(self, user):

        activation = Activation()
        activation.user = user
        activation.key = uuid.uuid4()
        activation.save()

        return activation.key


class Activation(models.Model):

    user = models.ForeignKey('MainUser')
    key = models.CharField(max_length=100, blank=False)

    create_time = models.DateTimeField(auto_now=True)

    is_active = models.BooleanField(default=True)

    objects = ActivationManager()

    def __unicode__(self):
        return u"user={0} key={1}".format(self.user, self.key)

    class Meta:
        verbose_name=u""


как сделать активацию через отправку на email активационную ссылку . Я хочу сделать true поле is active в админ панеле. Думаю что идея такая: После регистрации генерирую код и отправляю на email ссылку ../activate/code. После открытия этой ссылки делаю поле is active true. как это реализовать?

send_mail('activation JustSolve.kz', "hello world", settings.EMAIL_HOST_USER, ['knursultana@gmail.com'])


и как сделать чтобы отправлять письмо не только на gmail
  • Вопрос задан
  • 839 просмотров
Пригласить эксперта
Ответы на вопрос 1
Я для активации аккаунта использовал механизм восстановления пароля. Получилось, примерно, так.
views.py
...
        user.is_active = False
        user.save()
        context = {'user': user}

        current_site = get_current_site(request)
        site_name = current_site.name
        domain = current_site.domain

        use_https = request.is_secure()
        token_generator = user_is_active_token_generator
        extra_context = {
            'domain': domain,
            'site_name': site_name,
            'uid': urlsafe_base64_encode(force_bytes(user.pk)),
            'user': user,
            'token': token_generator.make_token(user),
            'protocol': 'https' if use_https else 'http',
        }
        context.update(extra_context)
        mail_message_template = 'путь до registration_email_user_not_is_active.html'
        mail_message = render_to_string(mail_message_template, context)

        send_mail('activation JustSolve.kz', mail_message, settings.EMAIL_HOST_USER, ['knursultana@gmail.com'])

tokens.py (он почти такой же как и django.contrib.auth.tokens)
from django.conf import settings
from django.contrib.auth.tokens import PasswordResetTokenGenerator
from django.utils import six
from django.utils.crypto import constant_time_compare, salted_hmac
from django.utils.http import base36_to_int, int_to_base36


class UserIsActiveTokenGenerator(PasswordResetTokenGenerator):

    def check_token(self, user, token):
        """
        Check that a password reset token is correct for a given user.
        """
        # Parse the token
        try:
            ts_b36, hash = token.split("-")
        except ValueError:
            return False

        try:
            ts = base36_to_int(ts_b36)
        except ValueError:
            return False

        # Check that the timestamp/uid has not been tampered with
        if not constant_time_compare(self._make_token_with_timestamp(user, ts), token):
            return False

        return True

    def _make_token_with_timestamp(self, user, timestamp):
        # timestamp is number of days since 2001-1-1.  Converted to
        # base 36, this gives us a 3 digit string until about 2121
        ts_b36 = int_to_base36(timestamp)

        # By hashing on the internal state of the user and using state
        # that is sure to change (the password salt will change as soon as
        # the password is set, at least for current Django auth, and
        # last_login will also change), we produce a hash that will be
        # invalid as soon as it is used.
        # We limit the hash to 20 chars to keep URL short
        key_salt = "django.contrib.auth.tokens.PasswordResetTokenGenerator"

        # Ensure results are consistent across DB backends
        joined_timestamp = '' if user.date_joined is None else user.date_joined.replace(microsecond=0, tzinfo=None)

        value = (six.text_type(user.pk) +
                 six.text_type(joined_timestamp) + six.text_type(timestamp))
        hash = salted_hmac(key_salt, value).hexdigest()[::2]
        return "%s-%s" % (ts_b36, hash)

user_is_active_token_generator = UserIsActiveTokenGenerator()

registration_email_user_not_is_active.html
Dear, {{ user.username }}!<br>
You join to {{ domain }}!<br>

url to activate <a href="{{ protocol }}://{{ domain }}/activate/{{ uid }}/{{ token }}/">{{ protocol }}://{{ domain }}/activate/{{ uid }}/{{ token }}/</a>

welcome!

urls.py
...
    url(r'^activate/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
        views.activate, name='activate')
...

views.py
def activate(request, uidb64=None, token=None,
             token_generator=user_is_active_token_generator,
             template_name='common/activate.html'):

    UserModel = get_user_model()
    assert uidb64 is not None and token is not None  # checked by URLconf

    try:
        # urlsafe_base64_decode() decodes to bytestring on Python 3
        uid = force_text(urlsafe_base64_decode(uidb64))
        user = UserModel._default_manager.get(pk=uid)
    except (TypeError, ValueError, OverflowError, UserModel.DoesNotExist):
        user = None

    if user is not None and user.is_active:
        validlink = True
        title = _('Link no longer relevant')
    elif user is not None and token_generator.check_token(user, token):
        user.is_active = True
        user.save()

        validlink = True
        title = _('Account activated')
    else:
        validlink = False
        title = _('Link not correct')
    context = {
        'title': title,
        'validlink': validlink,
    }

    return TemplateResponse(request, template_name, context)

При таком подходе не понадобится дополнительная модель Activation или какие-то поля в бд.

# Проверки должны находиться в django forms, а не во вьюхе.
validate_email(email)
len(password) >= 5
password != password2
User.objects.filter(username=email, is_active=True).exists()
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы