Am on Django 1.6
In my app I'd like to have a User object and a separate profile object. I'd like to avoid implementing a custom User object and instead just use a one-to-one relation to a model that has all the additional fields/info I want.
Whenever I do a query on a User object, 90% of the time I will want to retrieve this profile object. My thinking is that the best way to do this is to modify the get_queryset method of the default UserManager to always retrieve this related object via a "select_related" call.
Is there a way to do this?
Searching around this is the only resource i could find on the topic.
Override Django User Manager to only return active users in queries
Do I need to do it this way? Can I instead just somehow use the base User object?
Thanks in advance.
Since Django 1.5 you can create your custom user model. This eliminates the need of user_profile.
Related
I created a model ExtendedUser to extend the User Django built-in model class using the approach described in the official documentation:
https://docs.djangoproject.com/en/3.2/topics/auth/customizing/#extending-the-existing-user-model
so that I can benefit from the existing authentication features provided by Django.
That works all fine however I wonder now, whenever I want to create a new ExtendedUser, that means for every ExtendedUser, I also need to create an original User to fullfill the one-to-one relationship?
Or what else does it mean the following:
Assuming an existing Employee Fred Smith who has both a User and Employee model, you can access the related information using Django’s
standard related model conventions[...]
In a script to create objects, would this mean the following:
u1 = User.objects.create_user(username="u_1", email="u_1#abc.com", password="pw_u_1")
ext_u_1 = ExtendedUser.objects.create(id=u1.id, user=u1, prop_1="XYZ")
where
class ExtendedUser(models.Model):
user = models.OneToOneField(User, ...)
# More properties...
Yes, if you extend using OneToOne field, it will require to create both objects i.e. User as well as ExtendedUser to fulfil the one to one relationship.
But I would suggest to not use OneToOne field instead override the AbstractUser model provided by Django to create the ExtendedUserModel, even if you don't need anything extra in ExtendedUserModel now. It will help you to add any new fields, methods easily to your user model in future as well as you won't be needed to create two object for a single User.
Same has been suggested in Django docs as well. Reference:- https://docs.djangoproject.com/en/3.2/topics/auth/customizing/#using-a-custom-user-model-when-starting-a-project
I am trying to implement an SSO login, deriving all the authorization rights from saml response:
class SAMLServiceProviderBackend(object):
def authenticate(self, saml_authentication=None):
if not saml_authentication: # Using another authentication method
return None
if saml_authentication.is_authenticated():
attributes = saml_authentication.get_attributes()
user = User(username=saml_authentication.get_nameid())
user.first_name = attributes['givenName']
user.last_name = attributes['sn']
return None
in views I got something like
...
user = authenticate(saml_authentication=auth)
login(self.request, user)
...
login fails because of the missing save() method. The only way would be to inherit from User and override the save method. Trying this, I got the next errors with is_authenticated, get_and_delete_messages, and so on
Is there an easy way to insert a user object into session, without saving the user to database?
Something like:
request.session['user'] = authenticate(saml_authentication=auth)
I guess should be possible with some limitations, eg. you cannot save your data with a user being a FK.
I have tried this myself, I suspect that you can dynamically create a user instance in the authenticate() method just don't call user.save(), or overwrite the save() method to do nothing.
You might also need to hook up the user record between requests, so you might need to write your own serializer for the user and load that construct the user instance back from session.
I'm fairly certain that Django's session objects are required for the authentication backend. i.e. if you login, then Django needs to store a reference to this fact somewhere. Django generally uses it's database to do this, however, if you're not using a database with your app then you can look at caching sessions instead:
https://docs.djangoproject.com/en/1.11/topics/http/sessions/#using-cached-sessions
(I'm assuming you're not using a database judging by your question)
More importantly however, depending on your needs, you may need to look at creating / configuring, a custom User Model in order to get your backend to work:
https://docs.djangoproject.com/en/1.11/topics/auth/customizing/#substituting-a-custom-user-model
I'm a Django beginner (though I do have experience in web development using Sails.js + Angular) so bear with me.
I have an existing application that uses REST API in communicating between Sails.js backend and AngularJS frontend. Now, we've found the backend to be unsuited for our purposes, and we're going to swap to using Django in near-future. Sails.js automatically creates the REST methods for the controllers while Django doesn't, so I suppose I'm going to use something like Django Rest Framework to create the API.
So yeah, I've found corresponding features for most things. The on thing I haven't found yet is a replacement for a Sails.js feature called "policies". They are functions that can be executed on queries to certain controller actions, and can be defined as model-specific, model-controller action-specific, and request type specific. For example, you can have an "authAccess" policy that checks that the user of a request is authenticated, and the policy gets executed before the actual requested controller method gets executed. You can also use these to modify request objects before passing them to the controller. Now to my actual problem:
Let's say I have a User model that has a many-to-one relation with another model, let's call it Book, meaning a user can own many books, but a book can only have one owner. Goody good. Now, we have a logged-in user that is making a query to find all of his books. He makes a GET request to /book. I want to ensure that the returned Book objects are filtered so that ONLY HIS BOOKS are returned.
So basically in Sails I was able to write a policy that altered the request parameters to be like {user: loggedInUser} so the resulting Book results were automatically filtered. This was handy, since I was able to use the same policy to filter other models, too, like DVD or Friend or whatnot. My question is - what would be the best way to implement the same functionality in Django?
Have a look at the documentation:
http://www.django-rest-framework.org/api-guide/filtering/#filtering-against-the-current-user
Most likely you are better off overwriting the get_queryset method in a model viewset. And you can make this a generic approach by creating a base class for your views, something like:
from rest_framework import generics, viewsets, mixins, generics
class OwnerModelViewSet(viewsets.ModelViewSet):
def get_queryset(self):
"""
This view should return a list of all the records
for the currently authenticated user.
"""
return self.model.objects.filter(user=self.request.user)
All your model viewset classes can inherit from that class. It would require the foreign key field to be always named "user" though. If that is not the case here is a slightly hacky way how you could find a foreign key field to the User table. Use with care.
from django.db.models.fields.related import ForeignKey
from accounts.models import User
def _get_related_user(self, obj):
'''
Search for FK to user model and return field name or False if no FK.
This can lead to wrong results when the model has more than one user FK.
'''
for f in self.model._meta.fields:
if isinstance(f, ForeignKey) and f.rel.to == User:
return f.name
return False
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?
I have a field Foo with a ForeignKey that points to User. I need to create filter in the admin that only displays User that have at least one Foo. This would be easy with the development version of Django, but I am stuck with the 1.3.
I have seen here how to add a custom filter using the undocumented FilterSpec class. My problem is that it requires to modify the User model. I could inherit from User, but I already ave a setup where additional data is put into a Profile model wiith a one-to.one link to User.
Is there a less intrusive way to add a custom filter to the User model?
You can actually use the foreign key relation backwards in an ORM query.
User.objects.filter(foo__isnull=False)