I'd like to create a subset of Users that don't have a login... basically as a way to add a photographer field to photos without having a full blown account associated with that person (since in many cases, they'll never actually log in to the site). A caveat is that I'd also like to be able to enable an account for them later.
So, I think the question becomes what's the best way to set up a "People" table that ties to the User table without actually extending the User table with UserProfile.
A user profile (as returned by django.contrib.auth.models.User.get_profile) doesn't extend the User table - the model you specify as the profile model with the AUTH_PROFILE_MODULE setting is just a model which has a ForeignKey to User. get_profile and the setting are really just a convenience API for accessing an instance of a specific model which has a ForeignKey to a specific User instance.
As such, one option is to create a profile model in which the ForeignKey to User can be null and associate your Photo model with this profile model instead of the User model. This would allow you to create a profile for a non-existent user and attach a registered User to the profile at a later date.
Users that can't login? Just given them a totally random password.
import random
user.set_password( str(random.random()) )
They'll never be able to log on.
Supply your own authentication routine, then you can check (or not check) anything you like. We do this so if they fail on normal username, we can also let them in on email/password (although that's not what I'm showing below).
in settings.py:
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
'userprofile.my_authenticate.MyLoginBackend', # if they fail the normal test
)
in userprofile/my_authenticate.py:
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.models import User
class MyLoginBackend(ModelBackend):
"""Return User record if username + (some test) is valid.
Return None if no match.
"""
def authenticate(self, username=None, password=None, request=None):
try:
user = User.objects.get(username=username)
# plus any other test of User/UserProfile, etc.
return user # indicates success
except User.DoesNotExist:
return None
# authenticate
# class MyLoginBackend
From the documentation on django auth, if you want to use the User model, it's mandatory to have a username and password, there are no "anonymous accounts". I guess you could create accounts with a default password and then give the opportunity for people to enable a "real" account (by setting a password themselves).
To set up a "People" table that ties to the User table you just have to use a ForeignKey field (that's actually the recommended way of adding additional info to the User model, and not inheritance)
Using a model with a ForeignKey field linking to User might not work as you want because you need anonymous access. I'm not sure if that's going to work, but you might try what happens if you let it have a ForeignKey to AnonymousUser (whose id is always None!) instead.
If you try it, post your results here, I'd be curious.
The django.contrib.auth.models.User exists solely for the purpose of using default authentication backend (database-based). If you write your own backend, you can make some accounts passwordless, while keeping normal accounts with passwords. Django documentation has a chapter on this.
Another upvote for insin's answer: handle this through a UserProfile. James Bennett has a great article about extending django.contrib.auth.models.User. He walks through a couple methods, explains their pros/cons and lands on the UserProfile way as ideal.
Related
While searching online on how to accomplish custom authentication in Django I came across this and this article. Both of these articles specified the same instructions. Currently i have something like this. (Taken from first article)
class Client(models.Model):
email = models.EmailField(unique=True, max_length=100)
password = models.CharField(max_length=128)
Then in another python file I have this
from .models import Client
class ClientAuthBackend(object):
def authenticate(self, username=None, password=None):
try:
user = Client.objects.get(email=username)
return user
if password == 'master':
# Authentication success by returning the user
return user
else:
# Authentication fails if None is returned
return None
except Client.DoesNotExist:
return None
def get_user(self, user_id):
try:
return Client.objects.get(pk=user_id)
except Client.DoesNotExist:
return None
I just started using Django and have kind of skipped the model section for db interaction since in my current project I am using RAW and custom SQL due to certain reasons.
My question is where does the
user = Client.objects.get(email=username)
get its user from . Do I have to make an entry into a database ?
What I want to do is to create a user during runtime and not save to the database.I tried doing this
#The following creates and saves a user in the db
u =User.objects.create_user('john', 'lennon#thebeatles.com', 'johnpassword',cust_address="my_custom_address",cust_msg="Users custom message")
The above returns a Client.DoesNotExist exception.
My question is where does the
user = Client.objects.get(email=username)
get its user from
Apparently, Client is a models.Model. This means that represents a single record of the relevant table in your database, wherever that is depending on the relevant settings.py setting.
Therefore, the table representing that model can be created with the next Django migration and lots of other useful things Django allows for.
So essentialy the above statement instructs the Django ORM to fetch all Client records from that particular table with that specific email. If no such entries exist, none will be returned.
I tried doing this
u =User.objects.create_user('john', 'lennon#thebeatles.com', 'johnpassword',cust_address="my_custom_address",cust_msg="Users custom message")
This is where you complicate things a bit. The create_user method is not part of Django ORM, but part of the Django default auth model manager django.contrib.auth.models.User. You should either provide such a method yourself, or easier to just use the standard create method provided with the default Django model manager.
Not saving the user model even on some cache does not make sense at all, as it implies that the user registers each time he or she wishes to login.
Having said all those, I would strongly recommend you to read the official Django documentation. All the above are covered, the documentation is very comprehensive and not that long. You can then read and understand tutorials on the wild which may or may not be correct or up to date.
Take a good read specifically on the Customizing authentication topic, as it provides additional methods far easier for the beginner.
A great greetings community
My question is related with the kind of manage users and the schema users in Django, In beginning I ask to you apologize just in case that my questions can will be too "newbies" or without sense, I am starting to related me with the Django Users schemas and their different possibilities of work in the projects.
I have the following situation.
I am building an application in which I will have three differents user types:
Medical
Patient
Physiotherapist
I am using the default Django authentication scheme (django.contrib.auth).
Initially, I did think in this scheme of entities in which the User table is the auth_user table in where Django save the users created:
I have the is_patient, is_medical and is_physiotherapist fields like boolean attributes in the User table.
Like a particular detail I understand that in the Django default model User is not possible modify or add attributes or fields.
This is an important and powerful reason to I cannot add the is_patient, is_medical and is_physiotherapist boolean fields in User table.
A classic recommendation is extend the User model with a Userprofile table in which I add fields or attributes to User Model through of OneToOne relationship. A basic sample is such as follow:
Is of this way that I get that my users in Django can have the field photo and upload one in a given moment ...
Taking advantage of the previous,
The following schema can be suited or can be an alternative for manage user roles (patient, medical and physiotherapist user types) ?
I will have relationships between:
User medical and user patients
user physiotherapist and user patients
and so between them and other tables ...
With this approach these relationships don't will be affected?
The different users will be saved between the Users and UserProfile table.
Is this a good practice in the scalability sense? My tables could be crash or my database?
In addition, I also have seen other alternatives such as:
Role Table/Model
I will have a role table/model independent or separate and that this can be related with the Django User model (One User can will have many roles by example)
This approach can be useful when I want store exclusive information about of a role in specia?
Django Permissions and Authorization
I ignore or unknown the granularity grade that let will me work. Of a single way I have been see that the permissions and authorizations system let will me work with create and edit and remove operations ....
Here, can I see the groups creation?
For example a medical group and allocate them permissions and linked this permissions to the users that compose the group ? Is this another good alternative?
This option seem more single although I don't know if an user could make some operations according to the group privileges that have ... I don't know if this thinking is correct/right
AUTH_USER_MODEL Creating a Custom User model
My requirements for patient, medical and physiotherapist users, require build a custom user model?
In this situation, especially if you want to store different infos for Patients, Medics and Physiotherapists you can create a Model for each and have a OneToOne field for each to the User model.
class Medic(models.Model):
user = models.OneToOneField(User, primary_key=True)
# other fields
class Physio(models.Model):
user = models.OneToOneField(User, primary_key=True)
# other fields
class Patient(models.Model):
user = models.OneToOneField(User, primary_key=True)
# other fields
This way you can give different permissions/roles implicitly in your application logic for each type of user (and still use the groups and permissions that Django offers if you need them for special cases, eg ChiefMedical...).
You will have to define some methods for your application logic like
def user_is_patient(user):
...
If you follow this path it is a good idea to have good tests to make sure that you don't get unexpected things like a user who is a Medic and a Physio...
Django lets you subclass the user model as well. Under the covers it would do the same thing as the code above, so it is probably better to do it explicitly as shown above (this way it is less probable that you access attributes that don't exist in that object!)
Taking advantage of the previous, The following schema can be suited or can be an alternative for manage user roles (patient, medical and physiotherapist user types) ?
The schema you show isn't great because it makes you store the information for all user types in the same table (and with the same fields). For example, Medics and Physios will have a blood type field type like Patients which will probably not be defined.
The different users will be saved between the Users and UserProfile table. Is this a good practice in the scalability sense? My tables could be crash or my database?
There should be no scalability problems with this solution (as long as you don't have millions new entries writes every day) and you can always optimise the database at a further point. However, you will have to make sure that your app doesn't accept 'forbidden' entries (e.g. users with no Medic, Physio or Patient profile)
Here, can I see the groups creation? For example a medical group and allocate them permissions and linked this permissions to the users that compose the group ? Is this another good alternative? This option seem more single although I don't know if an user could make some operations according to the group privileges that have ... I don't know if this thinking is correct/right
You can (should) use Django's permission system to give permissions to your users. You can use them to give different rights to users of the same type (for example Medics that have more permissions than others... or have groups for chief physios...)
Django lets you assign permissions to a group.
But I don't think groups can replace the custom models for each user, since you want to store information for them. Having custom models and groups would be redundant and make your app harder to maintain.
My requirements for patient, medical and physiotherapist users, require build a custom user model?
This option wouldn't be great (unless it is your only option) because your app won't be reusable and you might have problems with some packages as well.
You can create a custom User model or not, in any case, you could have three separate models for storing pertinent data, depending on whether the user is patient, medical, physiotherapist, or any combination of these.
If your permissions scheme is determined solely by the role (patient, medical, physiotherapist) then you don't need to use Django's permissions system, because you know the role(s) of any user and you can, in the worst scenario, hardcode authorization rules.
I gave a glance at question's comments and I view some issues:
()
I realized that your user model does not match with the original data model since having get_medical_profile, get_patient_profile and get_physiotherapist_profile functions inside user model, with that you are assuming that any user could have multiple profiles at the same time, which isn't reflected neither in your profile models (Medical, Patient and Physiotherapist) using OneToOneField nor in original data model of the question, it's an important thing about abstraction and class-responsibility. The requirement (according the model below) seems to say "one user can have only one profile".
So.. I think this can be solved in a straightforward and clean way, you don't need to involve in overall authentication esquema like groups and permissions or adding additional attributes to user model:
class UserProfile(models.Model):
user = models.OneToOneField(User)
# common fields shared by medical, patient and physiotherapist profiles
class MedicalUser(models.Model):
profile = models.OneToOneField(UserProfile)
# medical fields here
class PatientUser(models.Model):
profile = models.OneToOneField(UserProfile)
# patient fields here
class PhysiotherapistUser(models.Model):
profile = models.ForeignKey(UserProfile)
# patient fields here
As you see, you can have a profile which contains common fields shared by all profiles. and each profile has an specific model.
In addition, you can check if user is medical by this small function below, then if there is no an medical profile associated with profile then it will raise exception and it means it's a profile unspecified:
def is_medical_profile(profile):
try:
profile.medical_user
return True
except:
return False
You can also use it in your templates (as a custom template tag) in this way:
{% if profile | is_medical_profile %}
With this approach you don't need to setup AUTH_USER_MODEL
I hope this improves your solution.
Additional notes:
Just in case you decide to have a custom user model, setup settings.AUTH_USER_MODEL and use it for foreign keys to User.
On a piece of text of awesome book Two scoops of Django says:
From Django 1.5 onwards, the official preferred way to attach
ForeignKey, OneToOneField, or ManyToManyField to User
Therefore, your user profile model would change as follows:
from django.conf import settings
from django.db import models
class UserProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL)
Yes, it looks a bit strange, but that's what the official Django docs advice.
#geoom #Ire #lorenzo-peña I 've created an user through Django admin site and I checked their attributes (is_medical, is_patient, is_physiotherapist) via python shell
In [6]: User.objects.filter(username='agarcial').values('is_medical','is_patient','is_physiotherapist')
Out[6]: [{'is_physiotherapist': True, 'is_patient': True, 'is_medical': True}]
For the moment in my views.py I am doing that an user sign in only when this be one of three user types (medical, patient or physiotherapist)
# Create your views here.
class ProfileView(LoginRequiredMixin, TemplateView):
template_name = 'profile.html'
def get_context_data(self, **kwargs):
self.request.session['Hi'] = True
context = super(ProfileView, self).get_context_data(**kwargs)
is_auth = False
name = None
# Check if in the request goes the user
user = self.request.user
# Check about of possible cases (For now is one profile)
if user.is_medical:
#if self.request.user.is_authenticated():
print (user.is_medical)
is_auth = True
profile=user.get_medical_profile()
#name = self.request.user.username
data = {
'is_auth':is_auth,
'profile':profile,
}
context.update({'userprofile':profile, 'data':data})
elif user.is_patient:
print (user.is_patient)
is_auth=True
profile=user.get_patient_profile()
data = {
'is_auth':is_auth,
'profile':profile,
}
context.update({'userprofile':profile,'data':data})
elif user.is_physiotherapist:
print (user.is_physiotherapist)
is_auth=True
profile=user.get_physiotherapist_profile()
data = {
'is_auth':is_auth,
'profile':profile,
}
context.update({'userprofile':profile,'data':data})
return context
def get_userprofile(self):
return self.request.user.userprofile
If I check the other possible combinations (User patient,medical and physiotherapist) this could work?
I think create groups for (Medicals, Patients, Physiotherapists) and binding users for the authorization topic, although I should review other things for authorization process such as django guardian for example?
How about this?
Probably some of you would tell that is a recurrent topic, but after reading many articles, it still seems very ambiguous to me. My question is about the best way to use and to extend the User model preserving the authentication (and others) mechanisms available in Django. However, I prefer to describe my design:
There are users (Patients) that can sign up providing basic info (first name, last name, birth date, gender, email, password). Preferably, email should replace the username.
When a Patient is in the application, it can register a new Patient (imagine a member of the family), but email and password are not required because they won't log into the system.
For the first part, Django doc propose to extend User with a OneToOne relation to a Profile. However, to replace username by email they propose then to create a custom User extending from an AbstractUser, as well as an associated UserManager. The second requirement is like doing a one-to-many relation from users to users. So, according to Django, which should be the best strategy: creating a completely new user model and the one-to-many user-user adding an specific attribute that distinguish between main users and family members? OR extending Django User with a Profile and then a one-to-many relation profile-profile? Which option preserves the best the benefits of Django user authentication and model administration?
Thank you for any comment, suggestion, example.
First, if you want to use email as username, use the Django custom user functionnality. It works well.
Then, note that it's not because you created your own User that you can't extend it with a Profile.
So, a good solution could be :
Create a Django custom User without trying to add specific fields to it (the one and only purpose here is to use email to log instead of username).
Create a PatientProfile class that have a one-to-one relatioship (blank=True) with User class.
This way, a patient that can log in will be related to a User instance and will use this instance for this purpose. On the other hand, the patient who can't log in won't be related to any User instance.
In the end, there's no problem to use OneToMany relationship with PatientProfile for what's you want to do.
I am trying to use django-password-reset (https://pypi.python.org/pypi/django-password-reset/0.2) to allow users recovering their passwords.
django-password-reset provides a form where the user can enter their username or email address, and tries to find one of those in the database.
In my project, the user has no username field - only the email field.
Thus, I need to make it search users by the 'email' field only, and not by the 'username' field, which does not exist in my system.
The projects documentation says there are attributes to change this behavior:
http://django-password-reset.readthedocs.org/en/latest/views.html.
However, I simply cannot find out how to set these attributes.
Can someone help?
Just override Recover view like so:
class MyRecover(Recover):
search_fields = ['email']
myrecover = MyRecover.as_view()
because there are two recover urls, you need to pass the one with signature first and then the overridden one and then the included one, seems not very DRY, but it's the only way to make the urls be dispatched correctly:
url(r'^recover/(?P<signature>.+)/$', 'password_reset_recover.views.recover_done',
name='password_reset_sent'),
# next we override our url, assuming your app name is called 'core'
url(r'^recover/$', 'core.views.myrecover', name='password_reset_recover'),
url(r'^/', include('password_reset.urls')),
The documentation for django-password-reset says that it uses django.contrib.auth.models.User (the django built in User model) to search for username or email. So here a username would exist.
If you want to change the functionality of the django-password-reset you can go into the forms.py file and change the form's search_fields variable (and other logic) so that it only searches by email.
Here is the hyperlink to the forms.py:
https://github.com/brutasse/django-password-reset/blob/master/password_reset/forms.py
I'd start with changing the PasswordRecoveryForm
I'm new to Django and python. I've done login forms but I need to know. How can I connect the contents of the page with the user.
For example: It's a Q&A site. When you logged in, It shows profile page with the questions that user asked before. How the datas are linked to the specific user ID in the model?
Can it be done using the User object? If so, could you give me some simple example with the script?
Thank you.
Anything that "belongs" to a user, should either have a ForeignKey or ManyToManyField (depending on whether the object is owned by one user or many) to User on it. Then you can either filter the model based on the User:
SomeModel.objects.filter(user=some_user)
# where `user` is the name of your foreign key field
Or you can access the model through the user via reverse relations, for example:
class SomeModel(models.Model):
...
user = models.ForeignKey(User)
# Later ...
some_user.somemodel_set.all()
The second method is more typical since you generally have the user already from the request, so in your view, you'd just do:
somemodels = request.user.somemodel_set.all()
To get all the SomeModels that belong to the currently logged-in user.