I am working on a project and I have decided to use Google App Engine for hosting (Django-nonrel). The website will have multiple types of users (inheriting from AbstractUser), and I want to be able to create permissions to control what a user can see/do. Since the native Django permissions do not work on Nonrel, I tried using permission_backend_nonrel, however it only works if you use the standard User model.
I have spent lots of time searching for how others have gotten permissions to work on Nonrel and AbstractUser, but have not found anything. It seems like I should give up on getting permissions to work and just create fields within the user models to replicate permissions. For example, if I want only some users to have the ability to change their email address, then I could do:
accounts\models.py
class UserProfile(AbstractUser):
address = models.CharField(max_length=40)
can_change_email = models.BooleanField(default=True)
customers\models.py
class CustomerProfile(UserProfile):
company = models.BooleanField(max_length=40)
In this scenario I could set 'can_change_email' and control this behavior in the views for UserProfile.
I would prefer to use the built-in permission system, but running out of ideas. Any suggestions?
I'd say you might have better luck creating separate one-to-one models to signify the difference between your users. Django expects you to have a single user model.
Another option is to use the normal User model and create proxy models that reflect the changes you want to have between users.
The first way:
class CustomerProfile(models.Model):
user = models.OneToOneField(User)
The second way:
class CustomerProfile(User):
class Meta:
proxy = True
Related
I have Django project for recording personal expenses and keeping personal budget.
I have created required models for the project and authorization using Django. However the idea is that each authentic user shall keep own expenses records, therefore needs likely separate database. I have researched Django documentation and it seems doest not provide answer to this. Probably there is no need to set up another database but to create unique model fields inherited from default admin user fields and store the data for each user in the single database.
Please advice correct approach for this task.
You can always extend the auth user model to include additional data. You can create a new model that has all the additional fields plus a one-to-one relationship with the django user model.
eg:
from django.db import models
from django.conf import settings
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL)
date_of_birth = models.DateField(blank=True, null=True)
...
Here, you should be able to use the default auth user fields plus the custom fields you need.
Django: When extending User, better to use OneToOneField(User) or ForeignKey(User, unique=True)?
I went through this thread and found that ForeignKey(with unique=True) is better than OneToOneField, but what about extending the class itself, I.e. here is the example
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
# some additional fields
OR
class UserProfile(User):
# some additional fields
Difference between these two approaches and pros/cons and which one should I use?
EDIT:
I can use AbstractUser as well
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
phone_no = models.CharField(max_length=10, blank=True)
and then mentioned AUTH_USER_MODEL = 'myapp.User' in settings.py
main concern is, what approach should I use, extending the class or ForeignKey ?
Duplicates:
What's the difference between OneToOne and Subclassing a model in Django
Django Model Inheritance versus OneToOne field
MORE EDIT
Forget about ForeginKey or OneToOne, assume only one of these two exist, now compare that with extending/subclassing approach
First, it is good to know there currently are several options how to extend the Django user model. Each has its purpose (but there is some overlap as well). Django docs are a bit confusing as it seems from this there are two options, i.e. proxy or OneToOneField. However this relates to the existing user model, as further on in the docs is dealt with custom user models.
So in practice there are four (common) ways to deal with extending the user model:
Proxy model (no new databasefields, just to change user model behavior, i.e. new ordering, new methods, etc.).
OneToOneField (extra datafields needed within existing Djang user model).
Custom user model with AbstractBaseUser (extra datafields
needed, and specific requirements regarding authenticaton process,
e.g. using emailaddress als id token instead of username).
Custom user model with AbstractUser (extra datafields needed, no
change to authentication).
Implementing option 3 and 4 a fresh database migration is needed, so these are only suitable for new projects.
This is a good link for more detail on this. I think option 2 and 4 are closest as both only want to extend to add more datafields. Writer seems in favor of option 2, but when starting a new project option 4 seems easier to me. Somewhere in the comments writer mentions risk of not being able to upgrade to new Django versions for option 3 and 4. Seems far-fetched to me, but I can't tell really.
There is no better way to do, the thing is if you do extend AbstractUser you need to redefine some functions so it may be longer but you have more control on what you wanna do with your user.
Make a OneToOne field on django default user is faster and also allow you to add your own user custom fields but you can use directly User default field in your custom object, and your custom field on the user :
from django.contrib.auth.models import User
class Employee(models.Model):
user = models.OneToOneField(User)
department = models.CharField(max_length=100)
You can do :
>>> u = User.objects.get(username='fsmith')
>>> freds_department = u.employee.department
So it really depends on what you want to do. You can do your User for example if you want to take the mail adress as the identification token (it's a common exmaple but you can do much more things :p).
Here is a good explanation (I place it on user but you can read the whole page it's pretty interesting when you dive into User and authentication into Django).
Hope it help.
I am skeptical about the benefits of a unique FK verses one-to-one, you could achieve a similar thing in the admin by using fieldsets so I would prefer to have an explicit one-to-one field on the model, making the nature of the relation more obvious.
The duplicate questions you linked to aren't specific to the auth User model and discuss one-to-one vs model inheritance generally. Technically they are both the same (i.e. model inheritance uses a one-to-one field)
So ultimately the choice comes down to semantics: is your related model a 'subclass' of the other, or just a link to further related info?
In the case of auth User you would ask yourself then: are there some extra fields that should be present for all users (eg gender, facebook id etc)? or some fields you want to omit from the Django User model (eg to use unique email address as username)?
In this case the obvious choice is to extend AbstractUser. If you can't imagine specifying null=True on your user profile model you should consider extending AbstractUser.
On the other hand there may be some data that is more analogous to the old UserProfile model (have a look how things were in old versions of Django before extending AbstractUser was supported: https://docs.djangoproject.com/en/1.4/topics/auth/#storing-additional-information-about-users)
Perhaps for example you have different types of users who may or may not have certain extra sets of fields. In this case it may make sense to have a one-to-one link to one or more 'profile' models.
I want to use two different models for django.contrib.auth module. The first one is the default User model provided by Django which is completely suitable for admin access (groups, permissions etc.) but the other one is customer model which has a lot of different attributes (city, locale, address etc.) compared to default User model. These user groups must use different tables and mustn't have any relation.
I created a Customer model inherited from AbstractBaseUser and a middleware class called ChangeBaseUser like this:
class ChangeBaseUser(object):
def process_request(self, request):
match = resolve(request.path)
if match.app_name == "myapp":
settings.AUTH_USER_MODEL = 'myapp.Customer'
else:
settings.AUTH_USER_MODEL = 'auth.User'
It's working but I'm not sure whether this is the proper way to do it because in documentation there is a section (link) that implies the convenient way is to assign a static value for default user model.
If this is not the proper way, do you have any suggestions for having multiple user models per module basis?
If your requirement is to keep admin users and customers separate, I don't see anything wrong with having multiple user models. At this point, the customer model is like any model, except it is very similar to the user model and that is perfectly fine if that works for you. The only disadvantage is that you will have to possibly duplicate many helpers django gives you for the Django user model such as auth backend or sessions for users. If you are willing to do all that, this seems perfectly fine.
If you wish however to utilize many of the django helpers you might want to create a very basic user model which will serve as a base for both admins and customers:
class User(AbstractBaseUser):
# use this for auth and sessions
class Admin(models.Model):
user = models.OneToOneField(UserBase, related_name='admins')
# ... other admin-specific fields
class Customer(models.Model):
user = models.OneToOneField(UserBase, related_name='admins')
# ... other customer-specific fields
This will allow you to reuse many of the things Django provides out of the box however it will incur some additional db overhead since more joins will have to be calculated. But then you can cache things for customers so you can get some of the performance back.
I don't like models.User, but I like Admin view, and I will keep admin view in my application.
How to overwirte models.User ?
Make it just look like following:
from django.contrib.auth.models import User
class ShugeUser(User)
username = EmailField(uniqute=True, verbose_name='EMail as your
username', ...)
email = CharField(verbose_name='Nickname, ...)
User = ShugeUser
That isn't possible right now. If all you want is to use the email address as the username, you could write a custom auth backend that checks if the email/password combination is correct instead of the username/password combination (here's an example from djangosnippets.org).
If you want more, you'll have to hack up Django pretty badly, or wait until Django better supports subclassing of the User model (according to this conversation on the django-users mailing list, it could happen as soon as Django 1.2, but don't count on it).
The answer above is good and we use it on several sites successfully. I want to also point out though that many times people want to change the User model they are adding more information fields. This can be accommodated with the built in user profile support in the the contrib admin module.
You access the profile by utilizing the get_profile() method of a User object.
Related documentation is available here.
I'm wondering what the common project/application structure is when the user model extended/sub-classed and this Resulting User model is shared and used across multiple apps.
I'd like to reference the same user model in multiple apps.
I haven't built the login interface yet, so I'm not sure how it should fit together.
The following comes to mind:
project.loginapp.app1
project.loginapp.app2
Is there a common pattern for this situation?
Would login best be handled by a 'login app'?
Similar to this question but more specific.
django application configuration
UPDATE
Clarified my use-case above.
I'd like to add fields (extend or subclass?) to the existing auth user model. And then reference that model in multiple apps.
Why are you extending User? Please clarify.
If you're adding more information about the users, you don't need to roll your own user and auth system. Django's version of that is quite solid. The user management is located in django.contrib.auth.
If you need to customize the information stored with users, first define a model such as
class Profile(models.Model):
...
user = models.ForeignKey("django.contrib.auth.models.User", unique=True)
and then set
AUTH_PROFILE_MODULE = "appname.profile"
in your settings.py
The advantage of setting this allows you to use code like this in your views:
def my_view(request):
profile = request.user.get_profile()
etc...
If you're trying to provide more ways for users to authenticate, you can add an auth backend. Extend or re-implement django.contrib.auth.backends.ModelBackend and set it as
your AUTHENTICATION_BACKENDS in settings.py.
If you want to make use of a different permissions or groups concept than is provided by django, there's nothing that will stop you. Django makes use of those two concepts only in django.contrib.admin (That I know of), and you are free to use some other concept for those topics as you see fit.
You should check first if the contrib.auth module satisfies your needs, so you don't have to reinvent the wheel:
http://docs.djangoproject.com/en/dev/topics/auth/#topics-auth
edit:
Check this snippet that creates a UserProfile after the creation of a new User.
def create_user_profile_handler(sender, instance, created, **kwargs):
if not created: return
user_profile = UserProfile.objects.create(user=instance)
user_profile.save()
post_save.connect(create_user_profile_handler, sender=User)
i think the 'project/app' names are badly chosen. it's more like 'site/module'. an app can be very useful without having views, for example.
check the 2008 DjangoCon talks on YouTube, especially the one about reusable apps, it will make you think totally different about how to structure your project.