How to change default django User model to fit my needs? - python

The default Django's User model has some fields, and validation rules, that I don't really need. I want to make registration as simple as possible, i.e. require either email or username, or phone number - all those being unique, hence good as user identifiers.
I also don't like default character set for user name that is validated in Django user model. I'd like to allow any character there - why not?
I used user-profile django application before to add a profile to user - but this time I'd rather make the class mimimal. But I still want to use the User class, as it gives me an easy way to have parts of site restricted only for users logged in.
How do I do it?

Rather than modify the User class directly or do subclassing, you can also just repurpose the existing fields.
For one site I used the "first_name" field as the "publicly displayed name" of a user and stuff a slugified version of that into the "username" field (for use in URLs). I wrote a custom auth backend to allow people to log in using their "public name" or their email address, and I enforce the uniqueness of both of those at registration time. This plays nicely with other reusable apps and doesn't introduce extra tables or queries.
For another site I didn't want usernames at all, just unique emails. In order to satisfy Django's need for a unique username, I just hashed the email address and used that as the username (you have to base64-encode the hash to squeeze it under 30 characters). Custom auth backend to allow login with email.
If backwards-compatibility weren't an issue, there are a lot of improvements I'd love to see made to django.contrib.auth and the User model to make them more flexible. But there's quite a lot you can do inside the current constraints with a little creativity.

I misread the question. Hope this post is helpful to anyone else.
#in models.py
from django.db.models.signals import post_save
class UserProfile(models.Model):
user = models.ForeignKey(User)
#other fields here
def __str__(self):
return "%s's profile" % self.user
def create_user_profile(sender, instance, created, **kwargs):
if created:
profile, created = UserProfile.objects.get_or_create(user=instance)
post_save.connect(create_user_profile, sender=User)
#in settings.py
AUTH_PROFILE_MODULE = 'YOURAPP.UserProfile'
This will create a userprofile each time a user is saved if it is created.
You can then use
user.get_profile().whatever
Here is some more info from the docs
http://docs.djangoproject.com/en/dev/topics/auth/#storing-additional-information-about-users

The Django User model is structured very sensibly. You really don't want to allow arbitrary characters in a username, for instance, and there are ways to achieve email address login, without hacking changes to the base model.
To simply store additional information around a user account, Django supports the notion of user profiles. While you don't need to rely on the built in support to handle this, it is a convention that is commonly followed and it will allow you to play nice with the reusable Django apps that are floating around in the ether. For more information, see here.
If you want to actually modify the core User model but also "play nice" with reusable apps that rely on it, you're opening a bit of a Pandora's Box. Developers make base assumptions about how the core library is structured, so any changes may cause unexpected breakage. Nonetheless, you can monkeypatch changes to the base model, or branch a copy of Django locally. I would discourage the latter, and only recommend the former if you know what you're doing.

You face a bit of a dilemma which really has two solutions if you're committed to avoiding the profile-based customization already pointed out.
Change the User model itself, per Daniel's suggestions
Write a CustomUser class, subclassing User or copying its functionality.
The latter suggestion means that you would have to implement some things that User does automatically manually, but I wonder whether that's as bad as it sounds, especially if you're at the beginning of your project. All you'd have to do is rewrite a middle-ware class and some decorators.
Of course, I don't think this buys you anything that 1 won't get you, except that your project shouldn't break if you svn update your django. It may avoid some of the compatibility problems with other apps, but my guess is most problems will exist either way.

There are anumber of ways to do this, but here's what I'd do: I'd allow a user to enter an email, username (which must contain at least one letter and no # symbols) or mobile number. Then, when I validate it:
Check for the presence of #. If so, set it as the user's email, hash it appropriately and set it as their username as well.
Check to see if it's only numbers, dashes and +. Then, strip the appropriate characters and store it as both mobile number and username (if you're storing the mobile number in another model for SMS purposes or something).
If it's not either, just set it as username.
I'd also validate the user/phone/email field similarly on login and look in the appropriate place so that if, say, a user signs up with their mobile number and then changes their username (for some other purpose), they can still sign in with their mobile number.

Related

Can you use two different custom user as auth user in Django?

So let's say i want to authenticate two different user (e.g students with its studentID, and teachers with its teacherID). and both let's say both have different ID pattern.
how should I do that with Custom User ? should I extend from AbsractBaseUser and use BaseUserManager for both of them in the same class or make different class for each students and teacher ?
if so, what should I do with AUTH_USER_MODEL in settings.py ?
can i write it like "AUTH_USER_MODEL = ('accounts.StudentAccount', 'accounts.TeacherAccount' ) ?
I appreciate any of your help and answer !!!
I think you may be over complicating the matter.
To authenticate a user, you need two pieces of information from them - one is public (like their username), the other is private, their password.
Once you have authenticated the user - confirmed they are who they say they are, that is, they have submitted valid credentials, next step is to figure out what they are authorized to do.
There are always two different steps - authentication and then authorization. Authentication confirms who you are, and authorization determines what you are able to do.
Now, in your scenario, students and teachers are logging in. The difference between a student and a teacher (besides having a different id pattern) is that they can do different things on the system.
So the problem is making sure you are giving the right authorization to the user.
The way they authenticate really doesn't matter. In other words, it doesn't matter if students are logging in with their email address and teachers are logging in with their teacherid, in the end - the authentication process is the same.
Now, let us get to Django. By default in Django a user is supposed to enter a username. This can be anything as long as it follows two rules:
Maximum length is 150 characters
It can only contain alphanumeric, _, #, +, . and - characters
Do we need to customize this part? Not really, as both studentid and teacherid will fit within those restrictions.
The next part is how do I differentiate between a "student" and a "teacher"? The easiest way to do this is to extend the user model by adding a custom flag to differentiate between a teacher and a student:
from django.contrib.auth.models import User
class UserType(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
flag = models.IntegerField(choices=((1, 'Student'),(2, 'Teacher')), default=1)
Now, when you create a user - simply set this flag to either 1 or 2, depending on what kind of user you are creating.
Remember, the authentication will not change - just the authorization.
You can then use this flag to further restrict what this user can do. Have a look at the documentation for some examples.

How to add custom-fields (First and Last Name) in django-registration 2.2 (HMAC activation Workflow)?

There are already some question on this but most of their answers are using models based workflow which is not a recommended way anymore according to django-registration. I am just frustrated from last week, trying to figure out how to add first and last name fields in registration form in HMAC Workflow.
I am using the HMAC workflow and extended the registrationform, then overwrite the save method to also save the fields that you want to add. Don't forget to add to override the views and make them your new form.
from registration.forms import RegistrationForm
class RegisterForm(RegistrationForm):
first_name = models.CharField()
I am not intimately familiar with django, but an easy solution would be to follow the default registration workflow to let your user register. Then when your user tries to login for the first time you present them with a form to fill with all the extra information you might need.
In this way you also decouple the actual account creation from asking the user for more information, creating for them an extra incentive to actually go through with this process ("Oh man why do I need to provide my name, let's not sign up" vs "Oh well, I have already registered and given them an email might as well go through with it")
If you would prefer to have them in one step, then providing what code you have already would help us provide better feedback

modeling user settings in django

I would like have additional settings tied to each user in my application (beyond, is_staff, is_admin etc etc). Basically I'd like to have different settings to customize their user experience (ie: don't show tooltips, how many rows to display in results tables, other flags for turning things on or off).
Are there best practices for adding these types of settings, or example model to do this without touching the django user object (in the past when i needed a quick user property, i just added it to my django source code, but obviously know that this is a horrible idea).
So when someone sucessfully logs in, I would grab the settings for the user and add them to the session.
I wasn't sure if there was a pretty way, or best practice for doing this.
As already said, use UserProfile. To store many flags in the same field there's django-bitfield.
Either put them in the user profile model, or create another model with a one-to-one to User.

Use Django User-Model or create a own Model?

I'm currently designing a Django based site. For simplicity lets assume that it is a simple community site where users can log in and write messages to other users.
My current choice is wether to use the buildin User-Model or to build something my own. I don't need much from the buildin User: there will be no username (you e-mail address is you username), but you an set an internal Name of your choice which can be used by multiple users (like Facebook). Additionally, I don't need the permission system, since access to others will not be based on groups. So I would end up using only the email, firstname, lastname and password fields from the buildin User and everything else would be placed in a UserProfile.
On the other hand, the buildin User system will come handy on the backend of the site, since there is the chance I will need a group based permission system there.
All in all, it looks to me, that I rather build my one User Model and use the buildin only for access to the admin backend.
Is there anything wrong with my reflections?
Is there anything wrong with my reflections?
Yes.
My current choice is wether to use the buildin User-Model or to build something my own.
There is a third choice.
http://docs.djangoproject.com/en/1.2/topics/auth/#storing-additional-information-about-users
everything else would be placed in a UserProfile
Correct.
build my one User Model and use the buildin only for access to the admin backend
Don't build your own.
Do this:
If you'd like to store additional
information related to your users,
Django provides a method to specify a
site-specific related model -- termed
a "user profile" -- for this purpose.
As the author of django-primate I would like to add some comments. Django-primate which easily lets ju modify the built in User model is meant for just that. You might need just something a little extra, then use django-primate.
But there are problems, although I do not think modifying the django User model per se is a problem at all. One problem is that the "users" are quite different, the admin user and some other user are often not related. This can cause problems when for example an admin is logged in and then wants to login to the site as a "normal user", they do not expect those accounts to be related and do not expect to be logged in automatically as the admin user. This causes headaches for no reason. It also causes a lot of other headaches to implement the recommended related Profile model, you often need to make sure there is a contrib user for every profile and a profile for every contrib user if you for example want to use the authentication decorators. Forms and administration of "users" make this even more cumbersome. In short: usually something will go wrong in this process at some point, it's a curse.
I have mostly abandoned the contrib User model for anything else but for admins. Building another user model is really what you want, but you also want the authenicating part for that user, hence the common use of django contrib User (using it for the wrong reasons). The best solution if you are in a situation like this is to build your own authenication for that custom user model. This is actually quite easy and I cannot recommend this approach enough. I think that the official recommendation is wrong and that there should instead be good tools for authenticating custom user models built into django.
You might want to have a look at the recently created django-primate: https://github.com/aino/django-primate
I once built a custom user model, inheriting from the default one. It works, however, I wouldn't recommend it.
Currently, you have some requirements, but over time they may change. Django's user system is quite straightforward, and using it allows to adapt more easily to some of the most common use cases.
Another aspect to think about, is that there are several applications already available that you can use, and that may require Django's users. Using your own model, may make usage of such modules much more difficult.
On the other hand, hacking the Django's user system in order to comply with your current requirements may be tricky.
Moreover, migrating a 'Custom-User' to a 'Django-User' is always possible, so you are not really closing that door.
Overall, I think it really depends on what you mean with 'user'.
If you mean just a registration, and no real interaction with the core Django features, then I think a separate model is enough, especially because you can migrate at any time, with relatively little effort.
However, if for your application a 'user' maps to something very similar to the what Django is for, then I would use the Django User-Model.

how to overwrite User model

I don't like models.User, but I like Admin view, and I will keep admin view in my application.
How to overwirte models.User ?
Make it just look like following:
from django.contrib.auth.models import User
class ShugeUser(User)
username = EmailField(uniqute=True, verbose_name='EMail as your
username', ...)
email = CharField(verbose_name='Nickname, ...)
User = ShugeUser
That isn't possible right now. If all you want is to use the email address as the username, you could write a custom auth backend that checks if the email/password combination is correct instead of the username/password combination (here's an example from djangosnippets.org).
If you want more, you'll have to hack up Django pretty badly, or wait until Django better supports subclassing of the User model (according to this conversation on the django-users mailing list, it could happen as soon as Django 1.2, but don't count on it).
The answer above is good and we use it on several sites successfully. I want to also point out though that many times people want to change the User model they are adding more information fields. This can be accommodated with the built in user profile support in the the contrib admin module.
You access the profile by utilizing the get_profile() method of a User object.
Related documentation is available here.

Categories