Question

So I have an app that takes a form, and sends and e-mail address to somebody, but I want a way to stick and activation URL generated by Django into that e-mail, and not have the form data commit to the database until that activation link is clicked. Is there any way to do this?

Was it helpful?

Solution

Based on the comments on my first answer, here's a reworked one more suited to your needs.

Create a model, e.g. ServiceHours, that next to the data you want to collect (hours done, supervisor_email, ...), has the following fields:

activation_key=models.CharField(_('activation key'), max_length=40, null=True, blank=True)
validated=models.BooleanField(default=False)

I'd suggest adding a post_save signal to the Model, so that whenever a new ServiceHours instance is created (by saving the form), the email to the supervisor is sent.

# Add this to your models file
# Required imports 

from django.db.models.signals import post_save
from django.utils.hashcompat import sha_constructor
import random

def _create_and_send_activation_key(sender, instance, created, **kwargs):
    if created:    # Only do this for newly created instances.
        salt = sha_constructor(str(random.random())).hexdigest()[:5]        
        # Set activation key based on supervisor email 
        instance.activation_key = sha_constructor(salt+instance.supervisor_email).hexdigest()
        instance.save()
        # Create email
        subject = "Please validate"
        # In the message, you can use the data the volunteer has entered by accessing 
        # the instance properties
        message = "Include instance hours, volunteer's name etc\n"
        # Insert the activation key & link
        messsage += "Click here: %s" % (reverse("validate_hours", kwargs={'id': instance.id, 'activation_key':instance.activation_key})

        # Send the mail
        from django.core.mail import send_mail # Move this import to top of your file ofcourse, I've just put it here to show what module you need
        send_mail(subject, message, sender, recipients)

post_save.connect(_create_and_send_activation_key, sender=ServiceHours)

Define a view to validate service hours based on an activation key

  # in views.py
  def validate_hours(request, id, activation_key):
      # find the corresponding ServiceHours instance
      service_hours = ServiceHours.objects.get(id=id, activation_key=activation_key)
      service_hours.validated = True
      service_hours.save()

In your urls.py, define an url to your validate_hours view:

urlpatterns += patterns('',
    url(r'^validate-hours/(?P<id>[0-9]+)/(?P<activation_key>\w+)', validate_hours, name='validate_hours'),

This has all been off the top of my head, so please excuse any errors. I hope you get the gist of the process and can extend according to your exact needs.

OTHER TIPS

You might want to set/unset the is_active flag on the user.

Conceptually:

  • When a user registers succesfully, be sure to set the flag to False;
  • Autogenerate a unique string that is tied to the user's ID and send the activation url via email;
  • In the activation view, decompose the key into the user ID and set the is_active flag to True;
  • In your login view, check whether the user trying to log in has is_active is True.

Then you'll be sure that users who are logged in have a confirmed email address.

The page in Django's documentation on user authentication provides all necessary information. For a sample login view, the chapter "How to log a user in" has one.

If you'd prefer to use a reusable app, django-registration might fit your needs perfectly.

(Post-reply addition:) why not commit the data to the database? The "waste" of having unactivated users residing in your database does not outweigh the effort you'd need to implement a solution that does not commit the data to the database. Moreover, it might be more than interesting to have an idea of the amount of unactivated users (and act accordingly).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top