I'm rolling my own custom registration module in Django based on django.contrib.auth. My registration module will have some extra functionality and help me reduce my dependency on other django modules that I'm currently using like django-registration and django-emailchange. I've run into a what-the-best-way-to-do-it problem here.
Note: All the user accounts are based on django.contrib.auth.models.User model.
When the user clicks the "sign-up" link, the request gets passed to my view named register. I have a custom form which has four fields — username, email, password1 and password2. The form is based on django.forms.Form. The form provides basic validation e.g. passoword1 and password2 are the email; the email/username do not exist.
When the data gets POSTed back to my register view, I call the is_valid() method of the form, after which, I create a new user by calling a Manager method called create_user() in django.contrib.auth.models.UserManager. I need to add more custom functionality at this point like sending activation emails, etc. As a best-practice method, where should this logic be? Should this be in a method of the User Model? Should it be where it is currently - the Manager of the Model? Or should this be placed into a custom save() method of my sign-up Form?
Thanks.
Different from Chris, I believe on the philosophy of fat models, thin views.
The more code you can factor inside models, the more reusable your codebase is. Views concerns should be simply managing the request/response cycle and dealing with GET/POST parameters.
In this case, sending activation emails is related to the event of creating a new User. For those cases, Django already provides this abstraction through signals.
http://docs.djangoproject.com/en/1.2/topics/signals/#topics-signals
So, as an example, you can have in your models.py:
from django.contrib.models import User
from django.db.models.signals import post_save
def send_welcome_email(self):
# Reusable email sending code
User.send_welcome_email = send_welcome_email
def welcome_emails(sender, instance, created, **kwargs):
if created:
instance.send_welcome_email() # `instance` is User
post_save.connect(welcome_emails, sender=User)
Similarly, you can have this for when a User is deleted, or everytime a User is saved, etc. Signals are a good abstraction to event-driven tasks.
My recommendation is to not re-solve a problem that django-registration solves quite nicely. It has a pluggable backend system that lets you customize it as much or as little as needed.
Related
I am implementing social-app-django (not the deprecated one; the one that relies on Python-social-auth) with django 1.11 (not using Mongo). My application will need to store and manipulate a lot of data on users other than that which is fetched from their social media accounts at login.
I don't need to fetch or collect any extra data when the user authenticates, but various actions they perform on my site will need to be saved to their user model. I am wondering which of the following approaches is preferred (I've searched extensively online, but can't find a specific explanation of why to use one vs the other):
Create my own user model in my app's models.py (call it MyUser) that doesn't extend anything special, and then add a function in the authentication pipeline that associates the social-app-django user with a corresponding instance of MyUser. Leave AUTH_USER_MODEL and SOCIAL_AUTH_USER_MODEL unchanged.
or...
Create my own user model in my app's models.py, and in the project's settings.py set AUTH_USER_MODEL and SOCIAL_AUTH_USER_MODEL to point to MyUser. Leave the pipeline unchanged. In this case, I was wondering whether someone could clarify what MyUser and its manager should extend, and what I need to import in modules.py (I am confused because a lot of stack overflow posts are referring to deprecated versions of this module and I keep getting errors). Also, in this case should I be setting both AUTH_USER_MODEL and SOCIAL_AUTH_USER_MODEL, or just one of them?
Do these two methods essentially achieve the same thing? Is one more reliable/preferred for some reason? Or, should I be doing both? Thanks very much for any assistance.
Another detail: I would like to be able to access the User database not only from the app I am currently building, but also from other apps (within the same Django project) that I will build in the future. Does this affect anything?
Since I see this has a decent number of views I will post the solution I eventually came to.
Both django and social-app-django (or any other social auth module) make use of the default User model for authentication. While it's possible to edit this model to add custom parameters, I don't recommend it. It's not good abstraction or modularization. If you make a mistake when configuring the model, you won't just break a specific feature on your site, but you might also break the authentication itself.
The only circumstances I can think of under which you'd want to edit the default user model itself is if you need to make changes that affect the authentication flow itself (for example, adding your own custom authentication provider).
It's much easier and safer to create a new model called UserProfile, with a required one-to-one relationship to a User object. Now, you can treat the User object as the authentication part, and the UserProfile object as the content/storage part. You won't have to mess with the User model very often, and the UserProfile model doesn't matter for authentication purposes. Note that in this configuration you should NOT need to change the AUTH_USER_MODEL or SOCIAL_AUTH_USER_MODEL fields in the settings.py file.
If you take this approach, you will need to add a custom step in the authentication pipeline in which you create a new UserProfile object and associate it with the User who is currently logging in.
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 simple webapp in Django for an iPhone app.
I want to prompt the user to review our product, but just once. I then don't want to show that prompt again.
So would the best practise way of implementing this to be to add a new entry to the user profile model with a bolean field: "reviewed" - and then set that flag when the user completes the action?
I would then check for that entry in my template and display or not, the prompt.
I've not yet worked with database models, extended the user model, or saved to custom DB fields, so any thoughts or examples on this would be most welcome. I'm a little nervous as my site has live users and I won't want to break the user tables.
If you are using MySQL or PostgreSQL, you can do some ALTER TABLE without loosing any data.
In Django, it is quite easy to add a profile for the user.
Make sure, to create the profile if it doesn't exist :
try:
profile = request.user.get_profile()
except UserProfile.DoesNotExist:
# If DoesNotExists, Create an empty one
profile = UserProfile(user=request.user)
profile.save()
More information here :
http://docs.djangoproject.com/en/dev/topics/auth/#storing-additional-information-about-users
http://www.djangobook.com/en/1.0/chapter12/#cn222
There are a variety of ways to do this. I suggest the following:
Django has a messaging framework, built by design to show messages to users only once when the software creates them. Whenever X is created/modified/deleted etc, you can add the message to the user via User.message_set.create(message='Whatever you like'). This will be shown to the user once. This relies on django sessions, which I assume you're using since you're relying on the built-in user model. These messages are stored in auth_message.
HTH