Different model field requirements for superuser vs normal user? django - django

Example(not true example):
I want the superusers to have to save on register their username and email.
and the normal users to save username, email, and a number(unique=True).
I wanted to use the user models django has, but I don't see how when the number has to be unique? or rather I originally wanted it to be the primary key, but only for normal users. Do I have to manually make two different user classes along with the permissions, authentication etc.? or is there separate user models for admin/user in django?
I tried(as a complete amateur, new to oop and django)... after gave up on using it as primary key, bc AbstractUser is fly.
Tried with onetoonefield, but couldn't make a combined form with UserCreationForm, bc "too many fields error". Also weird to have an important part of the user table be in a different table (or is it?).
something like (not 100% accurate):
#in models.py
class AdminUser(AbstractUser):
username
email
class NormalUser():
ontoonefield(AdminUser)
number(unique=True)
#in forms.py
class NormalUserForm(UserCreationForm):
class meta:
fields
class onetoonefieldForm(NormalUserForm):
class meta:
add_field += (number)
tried playing with required_fields, but again... number is unique
tried making two abstractUsers... permissions errors
thought about just making it non-unique and just checking on db insert that it's unique, but that seemed like a risk to the database, when it's vital it's unique.
Thank you for listening:)
Have a great day

Do I have to manually make two different user classes along with the permissions, authentication etc.? or is there separate user models for admin/user in django?
Django uses one built in User model and distinguishes three types of users using the attributes is_staff and is_superuser.
Normal user: is_staff=False, is_superuser=False
Staff user (can access the admin interface): is_staff=True
Super user (can do everything): is_superuser=True
If the default user model does not work for you, you can extend it or replace it.
Having the user decide their primary key, is not the intended default. The primary key is usually decided by the database, which also handles the uniqueness. If you would like to assign a unique number to each user, such as a customer number, I suppose it is easiest to extend the user model with a user profile.

Related

extending default User model in Django

I've written my first application Django 2.0.
Everything is working fine and the application is almost ready when I realized to replace id primary key field from default integer type to UUID to make database entry more secure.
When I searched for this how to change id of user table to UUID I got many tutorials extending AbstractBaseUser.
Here is I have written own User model.
account/models.py
class User(AbstractBaseUser):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
But I'm confused more with examples on different sources.
Every example is adding few more fields in extended model like
first_name
last_name
is_staff
is_admin
active
and functions as
def get_fullname(self):
def get_shortname(self):
etc.
I think all these fields and functions are there by default in AUTH_USER_MODEL.
Does extending AbstractBaseUser overwrites AUTH_USER_MODEL and it is required to add all fields which is there by default?
also, I'm using settings.AUTH_USER_MODEL as foreign key in different models. Should It be replaced by account.User model?
I'm also using django-allauth plugin to enable login using the social network and use email only for authentication. Do I require to add email field in the extended model with unique=True?
Django AbstractBaseUser provides only following fields: password, last_login, is_active. So if you are using custom User model inherited from AbstractBaseUser you need to define all other fields such as email manually.
As another part of question just adding AUTH_USER_MODEL = 'users.User' to your settings.py file should make everything works without replace code in your project.
UPD
If you need field like first_name, last_name, etc. to be includet to the model you can use AbstractUser instead of AbstractBaseUser.
As the Django documentation indicates, it's difficult to extend the User table after-the-fact, and not recommended at all for apps. A better way is to create an auxiliary table which has a 1:1 relationship with the user-id. Leave Django's user-table alone and just use this other table to pony-up to it.
The "Django Annoying" project, at https://github.com/skorokithakis/django-annoying#autoonetoonefield, has some very useful "juice" to make this much easier: an AutoOneToOneField. Whereas Django's foreign-key field will throw an error if an record doesn't exist, this field will automagically create one on-the-fly, thereby side-stepping the entire issue. (The documentation page linked-to above shows exactly how this is done.)

Custom Django Authentication

I have an model named Customers(username,password ..etc) and also an model named User(username,password...etc).
I want to create two different APIs with different authentication.
One should authenticate with the User username,password
and the second should authenticate using the Customers username,password.
Any idea on how can I do this?
Thank you!
I suggest the following options:
1.
I am assuming User model is the "real" user of your app. If this is true use the django's default User model class. It will work out of the box.
For the Customer model, make it inherit from AbstractBaseUser, this will give you password functionality out of the box and you can add other fields as per your need.
Now you can create 2 different urls for login. 1 url for user which checks in the User model and the other for the customer model. This avoids any confusion for everyone.
If you prefer a single url, you have to mention the model class along with username and password to know in which table to verify them.
2.
Create two profile models: UserProfile and CustomerProfile
Each will have a one to one relationship with the django's default User model.
Basically a User can have the profile of a "real" user or of a customer.
In this case when you are creating any User you have check if you want to attach a UserProfile or a CustomerProfile.
In this case it makes sense to just use a single login url. From the user's login information you can first fetch the user from the User table and then check if it is a customer or not by running a query in the CustomerProfile table.
I recommend you to use the django.contrib.auth.user class for your classical authentication. You can either inherit from that class or add a OneToOne relation to your own model as follows
from django.contrib.auth.models import User
class YourUser(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
For the rest of your question you should add some more details and even some pieces of your code.

Modeling accounts for different types of users in Django

Say that you have an application where different kind of users can sign: Firms, Lawyers, and Clients. A Firm has many lawyers; a lawyer has many clients. The views for a firm user are, of course, different from the views of a lawyer user; the two are different from the client user.
How would you model the three different users? I can think the following approach:
Three different models with a ForeignKey to User, each with their own fields, e.g.:
class Firm(models.Model):
user = models.ForeignKey(User)
class Lawyer(models.Model):
user = models.ForeignKey(User)
specialty = models.CharField(max_length=100)
class Client(models.Model)
user = modelsForeignKey(User)
Now you can create, for instance, consultations as a separate model using two ForeignKeys: to Lawyer and to Client; you can also add resources to a consultation (like documents, or stuff like that) by creating a model Resource with a ForeignKey to Consultation.
This approach makes it difficult to distinguish among users: how do you know whether a user is a Firm, for instance - you need to query the database several times or assign a Profile to the generic User object.
You could also add only a Profile to the User and include a Role, and then you channel the views and authentication based on user.get_profile().role.
How would you deal with this problem?
I would do what you suggest here:
You could also add only a Profile to the User and include a Role, and then you channel the views and authentication based on user.get_profile().role.
Create a profile with a choice field for the role. Create some decorators like #lawyer_only that make sure that your views are only accessibly by Lawyer role users.
You could also consider subclassing the User model (model inheritance):
http://docs.djangoproject.com/en/dev/topics/db/models/#model-inheritance
You will have to go with the option of multi-table inheritance http://docs.djangoproject.com/en/dev/topics/db/models/#multi-table-inheritance since the User class is not an abstract model.

Cannot assign - must be a "UserProfile" instance

I have a class UserProfile defined which takes the default user as a foreign key.
Now another class A has a foreign key to UserProfile.
So for saving any instance in class A, how do i give it the userprofile object.
Also, does making a class UserProfile mean that class user is still used and class UserProfile is just some other table?
I need to know this as I have to take care of the user profile creation, so I should know what gets stored where?
--
Confused
So for saving any instance in class A,
how do i give it the userprofile
object.
Create a app with a model which has a models.OneToOneField(User) or a models.ForeignKey(User, unique=True).
Make your project aware of your UserProfile by pointing to it from the settings.py file AUTH_PROFILE_MODULE = 'myapp.UserProfile'.
Read the documentation.
Also, does making a class UserProfile
mean that class user is still used and
class UserProfile is just some other
table?
Yes, your database will have both a auth_user and a user_profile table. This is due to the fact that using UserProfiles doesn't mean all user have to have profiles. Only the additional fields defined in the UserProfile model will be in the user_profile table.
I need to know this as I have to take
care of the user profile creation, so
I should know what gets stored where?
James Bennett created two nice apps which with a few hours of careful reading will be of great help especially when it comes to the user registration part. Go look at django-registration and django-profiles.
I assume your UserProfile model is intended to store additional information about your users. If so, there's documentation about the best approach to do this, which in brief is:
define a model with fields for the additional information you'd like to store, or additional methods you'd like to have available, and also add a OneToOneField from your model to the User model. This will ensure only one instance of your model can be created for each User.
Set AUTH_PROFILE_MODULE to myapp.MyModel, where myapp is the app containing the model MyModel which you want to use to store extra information about your users.

Anyone think django's user model is too tightly coupled with auth?

I'm trying to learn Django and I would like feedback from anyone who has any MVC/MTV/PHP/Ruby framework experience. Does anyone find that the user model is too tightly coupled with auth?
Background: When you first implement authentication for Django, you include the module django.contrib.auth
This will bring in several models like User, Group, Message etc. Let's focus on the User model as this is the one of the most important tables in any website.
In short the User table has these fields
User
username max_length 30, unique, [letters, digits, underscores]
password max_length 75
email max_length 75
...and about 8 other useful fields like first_name, last_name, etc.
Goal:
I want to remove username and use email as the login for every user. It's a pretty simple request that many websites use these days.
I don't want to monkey patch the core code since this will make upgrading more difficult later on. This means modifying the User model is out of the question. I only want to do a few simple and basic things I expect a few frameworks to do so let me address how Django does it.
Adding new fields to the User model
Django docs says to use create another table and insert the fields there. You will have a one to one relationship between the User table and the Profile table.
eg.
If You want to add an image field to each user you add it to the profile table. A join query is made every single time. They've even specified a constant to tell the framework what table to use:
AUTH_PROFILE_MODULE = 'accounts.UserProfile'
I don't think it's the best practice to have to do a join query every time I want a field that should belong to the user table.
Another option is to use the function add_to_class.
The django community has stated it's not good to define new fields outside of the main class because other developers who add methods won't know all the data members.
Editing old fields
The auth module does a check against two fields username and the hashed password. Looking at the above table I would need to change the username model to accept these properties. Length of 75 with all the valid characters of the email. The django suggests I check against the email field.
Two problems arise if I use the email field to auth against:
I need to write a new class to be used in a constant AUTHENTICATION_BACKEND, so it checks against the email field and I have an unused field called username.
Adding new methods
In MVC/MTV a design principle is to use fat models skinny controllers. Since the model is declared in auth, I'm not sure how one is supposed to add methods that act on the user model's fields. Since django suggests using a Profile model, I suppose they will have to go there.
Extending the User class
A small annoyance would be that I can't use the name 'User' and instead must use 'Users' or 'Accounts'. A bigger one is I don't think the auth would recognize this new module. Meaning I would have to rewrite a bunch functionality that is is present. This one doesn't bother me as it's something I expect to do in other frameworks.
Any comments are appreciated. I wouldn't ask all these questions and look for solutions if I wasn't truly interested in using django.
I agree that django's incessant clinginess to the auth models is absurd. My job requires me to create ultra scalable and very high load sites which sometimes require user authentication and djano's auth model + permissions does not fit with that.
Fortunately, it's not difficult to replace.
First, create a custom User model.
class User(models.Model):
...fields...
#Define some interface methods to be compatible.
def get_and_delete_messages(self):
def is_active(self):
def is_anonymous(self):
def is_authenticated(self):
def is_staff(self):
def has_perm(self, perm_list):
Second, create your own authentication back-end.
class LocalAccount(object):
"""
This checks our local user DB for authentication
"""
def authenticate(self, username=None, password=None):
try:
user = User.objects.get(alias=username)
if user.check_password(password):
return user
except User.DoesNotExist:
return None
def get_user(self, user_id):
try:
return User.objects.select_related().get(pk=user_id)
except User.DoesNotExist:
return None
#settings.py
AUTHENTICATION_BACKENDS = (
'helpers.auth.LocalAccount',
)
That should solve most of your issues, I don't even think all of the methods you would find on django.contrib.auth.User are necessary, I recommend trying it out.
The one gotcha here is that the admin may start to bitch, fortunately that's really easy to patch using simple python inheritance as well. That's another question though :)
At the end of the day your project's auth backend needs some sort of store for auth credentials. That the default auth backend is tightly coupled to the User model is not strange in this respect. It's easy enough to substitute your own definition for the user model if you write your own auth backend, as I have in the past.
I created my Profile model and use AUTH_PROFILE_MODULE, so I have complete control over my model, I can modify fields, add methods, etc. Now I'm thinking about using cache and writing middleware that will get profile from cache if possible.
To login using email you could write very simple auth backend:
from django.contrib.auth.models import User
from django.contrib.auth.backends import ModelBackend
class EmailModelBackend(ModelBackend):
def authenticate(self, username=None, password=None):
try:
user = User.objects.get(email=username)
if user.check_password(password):
return user
except User.DoesNotExist:
return None