django registration - allows multiple users for an email id - django

I am trying out django-registration. I found that it allows multiple registration for same emailid. I want to prevent that. What is the best way to do that?
ok, I see there is a subclass RegistrationFormUniqueEmail. Now, how to use this class? I changed this
def get_form_class(self, request):
return RegistrationFormUniqueEmail
But, it must be better to change this from my application rather than in source code. So, how do I do that?
thanks

Once you've added registration to your settings file, you can use the form in your views.py like so:
from registration.forms import RegistrationFormUniqueEmail
form = RegistrationFormUniqueEmail()
That's it. That will give you the form that you need and will take care of the unique email validation.

Related

How to subclass registration form in django-registration

I wish to have the user agree to a TOS and to also support unique emails. django-registration has two different subclassed registration forms that does this: RegistrationFormTermsOfService and RegistrationFormUniqueEmail.
Do I have to make my own sublcass of RegistrationForm and then provide both those features? If so, how would this be accomplished? Would the registration form live inside my app's forms.py or somewhere else?
A quick look at the source for the two classes shows:
class RegistrationFormTermsOfService(RegistrationForm):
"""
Subclass of ``RegistrationForm`` which adds a required checkbox
for agreeing to a site's Terms of Service.
"""
tos = forms.BooleanField(widget=forms.CheckboxInput,
label=_(u'I have read and agree to the Terms of Service'),
error_messages={'required': _("You must agree to the terms to register")})
class RegistrationFormUniqueEmail(RegistrationForm):
"""
Subclass of ``RegistrationForm`` which enforces uniqueness of
email addresses.
"""
def clean_email(self):
"""
Validate that the supplied email address is unique for the
site.
"""
if User.objects.filter(email__iexact=self.cleaned_data['email']):
raise forms.ValidationError(_("This email address is already in use. Please supply a different email address."))
return self.cleaned_data['email']
As you can see these two classes don't overwrite methods defined by the other so you should be able to just define your own class as being:
from registration.forms import RegistrationFormUniqueEmail, RegistrationFormTermsOfService
class RegistrationFormTOSAndEmail(RegistrationFormUniqueEmail, RegistrationFormTermsOfService):
pass
And it should function, however I have not tested this. As to where to place this class; forms.py is a good location.
Update:
A little reading at https://django-registration.readthedocs.org/en/latest/views.html which tells us that we can pass the view some parameters via the url definition; for instance a form class.
Simply use a URL like:
url(r'^register/$',
RegistrationView.as_view(form_class=RegistrationFormTOSAndEmail),
name='registration_register')

Cleanest way to implement multiple email system in django?

Hey everyone, I am pretty sure this is a fairly common problem.
So in order to register an account my site you need an email address from certain school domain (like facebook). This wouldn't be that big a problem until you start integrating other apps, like django-notification and django-registration and django-socialregistration into your site where they are sending email via user.email.
I have asked my users and most of them want an 'active_email' option - that means that they can change the email to their designated gmail or whatever.
I have come up with the following solution which isn't the cleanest of all:
First, I inherit from User in django.contrib.auth and call this new class MultipleEmailUser, with email=active_email and official_email=sch_email.
Then I override django.contrib.auth's UserManager to change the API slightly,
And the most painful part is to change all the source code that has User.object.find() to MultipleEmailUser.find().
Can someone suggest me a cleaner way? (My biggest headache arise from other apps only permitting to send email to User.email.)
You don't need - or want - to modify the User class. Just set up a UserProfile class with a OneToOneField back to User, and set the AUTH_PROFILE_MODULE setting. See the documentation.
Rather than a true datastore attribute, you could use a property called 'email' to expose access to whatever data you want.
Basic property syntax (from the python docs):
class C(object):
def __init__(self):
self._x = None
def getx(self):
return self._x
def setx(self, value):
self._x = value
def delx(self):
del self._x
x = property(getx, setx, delx, "I'm the 'x' property.")
In your case, you could create true datastore attributes named, for instance, auth_email and active_email. Then, the User.email property could perform some logic in its getter function, to determine which one to return (i.e. if active_email is set, return it; otherwise, return auth_email)
It's worth noting that the syntax for property has undergone some flux. As of python 2.7, it can be implemented in a more readable way, as a decorator:
class User(BaseModel):
#property # email
def email(self):
if self.active_email:
return self.active_email
return self.auth_email

How to make multiple user types when signing up?

I'm using Django 1.2 and I want to have two user types (one for companies and one for consultants). I will either use an object in my model (something like a boolean for is_company or is_consultant) or Django's groups to distinguish them--depending on which is easier for this problem. I guess it wouldn't be much of a problem if I weren't a total noob ;)
I'm using django-registration for my authentication backend, and I will have a separate form on my webpage for each user type (company vs consultant). I don't think it is best to create two different views that are almost identical for the two cases, so I'm wondering what the best way is to identify/register the users who signed up as either of the two types.
Thanks for your help.
Do you want the user to pick if they are a consultant or company when registering? If so, you can create your own form by subclassing the RegistrationForm and then passing your new form into the parameters for django-registration (Read the doc on how to do that.)
To subclass the form and add the additional field you would do something like so:
from registration.forms import RegistrationForm
USER_TYPES = (
('consultant', 'Consultant'),
('company', 'Company'),
)
class MyRegistrationForm(RegistrationForm):
user_type = forms.ChoiceField(choices=USER_TYPES)
From then, you should catch the signal and do as you need with the form data django-registration has great documentation
Hope that's what you were lookign for.
Rather than looking in the POST, you can pass the information in the query string.
So one "button" (which is really just a link) links to /form?type=consultant, and the other links to /form?type=company and then you can grab it from the GET information

Django custom managers - how do I return only objects created by the logged-in user?

I want to overwrite the custom objects model manager to only return objects a specific user created. Admin users should still return all objects using the objects model manager.
Now I have found an approach that could work. They propose to create your own middleware looking like this:
#### myproject/middleware/threadlocals.py
try:
from threading import local
except ImportError:
# Python 2.3 compatibility
from django.utils._threading_local import local
_thread_locals = local()
def get_current_user():
return getattr(_thread_locals, 'user', None)
class ThreadLocals(object):
"""Middleware that gets various objects from the
request object and saves them in thread local storage."""
def process_request(self, request):
_thread_locals.user = getattr(request, 'user', None)
#### end
And in the Custom manager you could call the get_current_user() method to return only objects a specific user created.
class UserContactManager(models.Manager):
def get_query_set(self):
return super(UserContactManager, self).get_query_set().filter(creator=get_current_user())
Is this a good approach to this use-case? Will this work? Or is this like "using a sledgehammer to crack a nut" ? ;-)
Just using:
Contact.objects.filter(created_by= user)
in each view doesn`t look very neat to me.
EDIT Do not use this middleware approach !!!
use the approach stated by Jack M. below
After a while of testing this approach behaved pretty strange and with this approach you mix up a global-state with a current request.
Use the approach presented below. It is really easy and no need to hack around with the middleware.
create a custom manager in your model with a function that expects the current user or any other user as an input.
#in your models.py
class HourRecordManager(models.Manager):
def for_user(self, user):
return self.get_query_set().filter(created_by=user)
class HourRecord(models.Model):
#Managers
objects = HourRecordManager()
#in vour view you can call the manager like this and get returned only the objects from the currently logged-in user.
hr_set = HourRecord.objects.for_user(request.user)
See also this discussion about the middelware approach.
One way to handle this would be to create a new method instead of redefining get_query_set. Something along the lines of:
class UserContactManager(models.Manager):
def for_user(self, user):
return super(UserContactManager, self).get_query_set().filter(creator=user)
class UserContact(models.Model):
[...]
objects = UserContactManager()
This allows your view to look like this:
contacts = Contact.objects.for_user(request.user)
This should help keep your view simple, and because you would be using Django's built in features, it isn't likely to break in the future.
It seems necessary to use the middleware to store the user information.
However, I'd rather not modify the default ModelManager objects, but hook it upto a different manager, that I will use in the code, say in your case user_objects instead of objects.
Since you will use this only within views that are #login_required you dont need all the complex error handling in the Middleware.
Just my 2ยข.
Or even simpler and use foreign key to retrieve queryset.
If you have model like that
class HourRecord(models.Model):
created_by = ForeignKey(get_user_model(), related_name='hour_records')
You can query HourRecords in a view by user with simply:
request.user.hour_records.all()

Saving profile with registration in Django-Registration

In Django-Registration it says you can save a custom profile when you save a user.
But I have no idea what the documentation is asking me to do. Here is what they say:
To enable creation of a custom user profile along with the User (e.g., the model specified in the AUTH_PROFILE_MODULE setting), define a function which knows how to create and save an instance of that model with appropriate default values, and pass it as the keyword argument profile_callback. This function should accept one keyword argument:
user
The User to relate the profile to.
Can someone give me an example of the function that needs to be created and how to pass it as a argument?
You can pass the callback function in your urls.py file.
from mysite.profile.models import UserProfile
url( r'^accounts/register/$', 'registration.views.register',
{ 'profile_callback': UserProfile.objects.create }, name = 'registration_register' ),
Substitute your own function for UserProfile.objects.create as needed.
This is covered in this blogpost and expanded on in my answer to another question on the same issue
django-registration sends a signal at various events happening - registration and activation. At either of those points you can create a hook to that signal which will be given the user and request objects - from there you can create a profile for that user.
The signal from django-registration
#registration.signals.py
user_registered = Signal(providing_args=["user", "request"])
Code to create profile
#signals.py (in your project)
user_registered.connect(create_profile)
def create_profile(sender, instance, request, **kwargs):
from myapp.models import Profile
#If you want to set any values (perhaps passed via request)
#you can do that here
Profile(user = instance).save()
For anyone who met this problem, I think this blog post is a good tutorial: http://johnparsons.net/index.php/2013/06/28/creating-profiles-with-django-registration/.