I've read a few posts on inheritance of the User model for other models in Django, but I want a user to have a particular parent user, i.e. the User model inherits itself.
I'm not sure how to do this as I'd surely have to edit the django.auth.contrib model for User wouldn't I?
Thanks in advance for any tips.
Firstly, don't edit the source code in Django. That's a big mistake it'll make your code horrible to maintain - Whatever you're trying to do, you really don't want to change the Django source.
I'm not completely clear what you're asking, but it sound like you might need to create a new model that inherits from User and add a ManyToMany field to self on your model.
from django.contrib.auth.models import User
class ExtendedUser(User):
parent = models.ManyToManyField("self", symmetrical=False)
Your new model will now have all the fields and methods of Django's User class plus your extra parent field. The parent field on any particular ExtendedUser object will reference another ExtendedUser object.
As I say I'm taking a guess at what it is you're trying to do (If I've got it right, then you might find it helpful to do a bit of reading on model inheritance and class inheritance in general - maybe seek out a few tutorials on the subject too)
Related
Hi All!
I have a model structured something like this
class BaseUser(models.Model):
user_data = models.ForeignKey(settings.AUTH_USER_MODEL) #External Auth User Model
class Teacher(BaseUser):
pass
class Student(BaseUser):
pass
And I am adding all the models to Django admin like so.
for model in get_models(get_app('MyApp')):
admin.site.register(model)
In the admin panel, I can create/view a list of BaseUser, Teacher, and Student. Where Teacher/Student are subsets of BaseUser.
The Question
When a new user is created, it is automatically a BaseUser.
Is there a way to change the class of an user from BaseUser to Teacher or Student in the admin panel?
No there's no builtin way to do it in admin. You either have to code it yourself or if you want to create Teacher do it from it's admin create view.
It's not only about python class of model but also database representation. For each model that use concrete inheritance, special table is created that holds additional fields for the model subclass and automatically created OneToOneField to parent. Details here.
Edit:
Try to specify parent link field which may be manageable from admin and so it'll allow you to create e.g. new Teacher linked with already existing BaseUser.
Edit:
Specifying parent link will not help as well because that field will not appear in admin.
I'm creating an app in Django and so far I have been using an extended user model like so:
class MyUser(AbstractBaseUser):
...
with all the user and profile info, but I see a lot of people creating different models for the profile and the user itself on stack overflow, using OneToOneField, although those are mostly old questions.
My question is: which is better and, if there isn't a best among them, what are the advantages for each solution?
thanks!
It depends on what you want to do -- if you're happy with the User model as it stands in the latest version of Django you should just use that -- it's easy and you'll get a lot functionality that goes along with it -- for example a pretty good permission system, and you can be sure to be compatible with all third party modules. But if you thing you'll need to expand on the User model, it's pretty straightforward how to do it. You might find that in the future you need to add more methods to your model than you expected.
The examples that you see with separate UserProfile / User model are mostly a legacy of django < 1.5, where that was the recommended way to extend the User model. There's no reason to follow that pattern any more -- it's a lot more work to have to use two models where you just want one model
**2019 Update**
If you are starting a new Django project, you should always create your own custom user model that inherits from AbstractUser, as per the Django documentation, i.e.
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
pass
even if you don't need any additional functionality. The reason for this is that for very low effort, you are making it easy to customize your user object in the future. It's very laborious to replace the built-in User object with your own after you have run the initial migrations, unless you're able to delete all of your data and migrations and start over.
I find some useful information in Django docs:
Extending Django’s default User¶
If you’re entirely happy with Django’s User model and you just want to
add some additional profile information, you could simply subclass
django.contrib.auth.models.AbstractUser and add your custom profile
fields, although we’d recommend a separate model as described in the
“Model design considerations” note of Specifying a custom User model.
AbstractUser provides the full implementation of the default User as
an abstract model.
And:
Model design considerations
Think carefully before handling information not directly related to
authentication in your custom User Model.
It may be better to store app-specific user information in a model
that has a relation with the User model. That allows each app to
specify its own user data requirements without risking conflicts with
other apps. On the other hand, queries to retrieve this related
information will involve a database join, which may have an effect on
performance.
So if I reads it correctly, it means if the fields are related to authentication, then you should consider substitute the original User model. But if it's not related, like profile fields, such birthday, or profile_image, then you might want to create a standalone app that reference the original User model.
And a good tutorial I found: http://riceball.com/d/content/django-18-tutoria-52-adding-user-profile
A ForeignKey is to create a one-to-many relationship. In other words, it will return a queryset. For example, a single car has many wheels, but one wheel isn't attached to several different cars.
A OneToOneField will create a relationship between strictly two objects. For example, the rim belongs to the front-left tire, and only that tire has that rim.
Does that make sense?
In Django you have some naturally defined User class. My app also has a User class defined (they dont conflict, that's not the question)
My question is, since these two User classes conceptually represent the same thing (well, users) then it would be natural to integrate them. That is, have a single User class that contains all methods and variables of both classes.
What is the best way to achieve this?
There are (at least) two possibilities:
1) Use the 'custom user' functionality of Django (since Django 1.5), or
2) Use a OneToOneField to the django.contrib.auth User from your own user class.
The first allows you to customize more, but you might get some problems if you try to use third-party-apps that are either not ready for custom users or need specific properties of the stock User. For example, Django Guardian doesn't work if you remove the User-Group relationship.
The second is less intrusive, but doesn't allow you to customize the existing fields of User. Also, you need to manually create the instance of your own user class at registration time.
You should read the documentation about Extending the existing User model.
If you wish to store information related to User, you can use a one-to-one relationship to a model containing the fields for additional information. This one-to-one model is often called a profile model, as it might store non-auth related information about a site user. For example you might create an Employee (note: called MyUser below) model:
from django.contrib.auth.models import User
class MyUser(models.Model):
user = models.OneToOneField(User)
newfield1 = models.CharField(...)
AUTH_USER_MODEL = 'myapp.MyUser'
Django 1.5+ allows us to add custom fields to a User. I want to use this fact, but I don't necessarily know what is good practice. Here is a situation I am confused on how to handle the models.
Given the option to add fields to User, if a project only has one type of User, lets say a Student model, can I simply add student-specific fields to User? I am new to Django, but I believe the alternative would be to set up general User settings, and create a Student model, and a one-to-one unique field in it call user.
Should you ever expand a Django User's fields to mimic that of a model, even if the project is guaranteed only to have one type of user?
If you only have one type of user and are using Django 1.5+, I would recommend taking advantage of the new AbstractUser. Extending Django's default user
As an example where you want to add date of birth and favorite color:
#myusers/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
class MyUser(AbstractUser):
dob = models.DateField()
favorite_color = models.CharField(max_length=32, default='Blue')
If you need more flexibility you can extend the AbstractBaseUser instead of AbstractUser, but for most basic cases you should only need AbstractUser.
Also note that in either case, you'll need to reference your user model by using settings.AUTH_USER_MODEL.
Using out example above and assuming the app it was defined in is called myusers:
#settings.py
AUTH_USER_MODEL = 'myusers.MyUser'
The method you mention of creating a Student model with a one-to-one field to the User model still works, but is not as clean (there are still cases where it makes sense if you have multiple kinds of users).
I don't normally like to reference books in answers, but I found that Two Scoops of Django's, Chapter 16 on the User model gave a much clearer explanation of where the different options are appropriate than the current version of the online Django docs. The book is overall a very useful intro to Django and was written based on 1.5. You'd have to buy the book or find someone who has it, though... (FYI: I don't get any money recommending this).
You could also take a look at this SO question/answer: https://stackoverflow.com/a/14104748/307293
You shouldn't touch the django contributed User model (from the authentication framework). This will break upgrades and you do not know what other consequences it might have.
There are two basic ways to do this:
If you just need to store additional information about a user, but don't need to change how the authentication/authorization mechanism works, create a model and add a OneToOneField to the User model. In this model, store any other miscellaneous information.
If you want to change how authentication works you can create your own User model and have django use that (1.5+ only).
i finally can make my Django+Auth app works. I add the extra information to the user as the docs say. Now, i've a simple question. When i'm building a model that is related to the user, which user should i relate to? To auth.models.User or to my accounts.UserProfile?
An example: I've a model for Product, and the Product belongs to a user. Which would be the best option:
class Product(models.Model):
user = models.ForeignKey(auth.models.User)
or
class Product(models.Model):
user = models.ForeignKey(accounts.UserProfile)
I'm currently using auth.models.User, becouse i can issue a get_profile, but some friend told me that i was wrong.
Thank you!
You're doing the right thing.
UserProfile is just an extension of the User model.
And logically you're making a relation of a object with an object, not a relation of a object with some extra information.
Also, as you mentioned, you can always issue the 'get_profile' to get the extra data.