In the Django project I work on, the built in ('add', 'change', 'delete') permissions are next to useless for us, and only confuse our users in forms; we don't use the Django admin, it often doesn't make much sense for us to have three permissions instead of one edit permission, and our models are more granular than the objects we want to assign permissions to (as a made-up example, it doesn't make sense to have seperate permissions for an Invoice and an InvoiceLine - they're conceptually the same thing).
Anyway, at the moment I'm accomplishing this by subclassing each model from a custom abstract base model which has default_permissions = () in it's Meta, plus some ugly hacks to make the permissions from third-party models go away. Is there any way I can make Django not create those three permissions by default?
If you don't use the admin then just don't bother about the default permissions. They are not enforced by default anywhere else. Feel free to create your own Permission and check that the user has this in your edit views, with permission_required for function views and PermissionRequiredMixin for class based view (and Django>1.9).
Related
Ran into a problem that has me scratching my head, documentation hasn't really pulled me any luck so I figured I'd see if anyone else has been in this situation. So let's say I have a model (among others):
Organization
That sort of acts like a psuedo-tenant. The thing is, users within my app may or may not have permissions to multiple organizations, some only 1, some this, some that. Point is, there's no clear structure on where permissions lay for each user. By default it should be none as it is now until manually granting, but instead of granting permissions to all or no organizations has anyone ran into a similar situation of being in need to control permissions in a granular/dynamic fashion? It is important to note that these 'organizations' are loaded dynamically via an API to an external product.
I realize this can be done by crafting my own sort of permissions system outside of Django but my main question is can this be done with conventional Django permissions or is this out of scope?
Thanks
You need object-level permission
As already mentioned, you could use something to help you with the object permissions, like django-guardian. However, if it is for one model and it is something simple, consider also defining a custom permission in your organisation model:
class Organisation(models.Model):
# your fields
class Meta:
permissions = (('my_shiny_permission', 'Some description for it'),)
And then in your views you can define the logic for it:
def my_view(request):
if request.user.has_perm('my_app.my_shiny_permission'):
# do something
More about custom permissions - here.
I know how to make custom user models, my question is about style and best practices.
What are the consequences of custom user model in Django? Is it really better to use auxiliary one-to-one model?
And for example if I have a UserProfile models which is one-to-one to User, should I create friends relationship (which would be only specific to my app) between UserProfile or between User?
Also all 3rd-party packages rely on get_user_model(), so looks like if I don't use custom user model, all your relations should go to User, right? But I still can't add methods to User, so if User has friends relation, and I want to add recent_friends method, I should add this method to UserProfile. This looks a bit inconsistent for me.
I'd be glad if someone experienced in Django could give a clear insight.
Also all 3rd-party packages rely on get_user_model(), so looks like if I don't use custom user model, all your relations should go to User, right? But I still can't add methods to User, so if User has friends relation, and I want to add recent_friends method, I should add this method to UserProfile.
I have gone down the "one-to-one" route in the past and I ended up not liking the design of my app at all, it seems to me that it forces you away from SOLID. So if I was you I would rather subclass AbstractBaseUser or AbstractUser.
With AbstractBaseUser you are provided just the core implementation of User and then you can extend the model according to your requirements.
Depending on what sort of 3rd-party packages you are using you might need more than just the core implementation: if that's the case just extend AbstractUser which lets you extend the complete implementation of User.
I would definitely recommend using a custom user model - even if you use a one-to-one with a profile. It is incredibly hard to migrate to a custom user model if you've committed to the default user model, and there's almost always a point where you want to add at least some custom logic to the user model.
Whether you use a profile or further extend the user model should then be based on all considerations that usually apply to your database structure. The rightâ„¢ decision depends on the exact details of your profile, which only you know.
I am trying to understand why, when adding a custom Admin site for a django app, one needs to add both the model and the admin function. Say, you have an application called Story, and thus the admin site will be called StoryAdmin. When registering this on the django administration interface, you need to add this line:
# Registering all the changes to admin.site
admin.site.register(Story, StoryAdmin)
My question is, is there a way to just do this:
admin.site.register(StoryAdmin)
Adding only one thing, not two, because this makes things simpler, and there is a smaller chance for an error, and the code just looks less redundant. It would make things look much better, because in the end, you could have a clean list of all the admin panels:
admin.site.register(
StoryAdmin,
SomeAdmin,
FooAdmin,
)
That's not how admin.site.register is built. It expects a Model and then optionally the ModelAdmin with which to display that Model:
def register(self, model_or_iterable, admin_class=None, **options):
"""
Registers the given model(s) with the given admin class.
The model(s) should be Model classes, not instances.
If an admin class isn't given, it will use ModelAdmin (the default
admin options). If keyword arguments are given -- e.g., list_display --
they'll be applied as options to the admin class.
If a model is already registered, this will raise AlreadyRegistered.
If a model is abstract, this will raise ImproperlyConfigured.
"""
This allows you to use the same ModelAdmin on multiple Models (which can be desirable when, for example, you subclass a model off the same abstract Model).
It doesn't suit your style but it's just one of those things you just have to accept and get on with.
That's a good question, it could have been designed that way, but that's not the case.
I asume the main reason is to allow the admin class to be optional and use the default base ModelAdmin class for simple cases and to allow to use the same ModelAdmin subclass with many models, see implementation at: https://github.com/django/django/blob/master/django/contrib/admin/sites.py#L52-101
Also you don't need to define the class yourself if you need to customize a ModelAdmin, you can just pass kwargs to the register function:
admin.site.register(Story, list_display=['field1', 'field2'])
So that's my bet, they try to minimize the boilerplate when registering a model and allow it to be more flexible.
I'm currently designing a Django based site. For simplicity lets assume that it is a simple community site where users can log in and write messages to other users.
My current choice is wether to use the buildin User-Model or to build something my own. I don't need much from the buildin User: there will be no username (you e-mail address is you username), but you an set an internal Name of your choice which can be used by multiple users (like Facebook). Additionally, I don't need the permission system, since access to others will not be based on groups. So I would end up using only the email, firstname, lastname and password fields from the buildin User and everything else would be placed in a UserProfile.
On the other hand, the buildin User system will come handy on the backend of the site, since there is the chance I will need a group based permission system there.
All in all, it looks to me, that I rather build my one User Model and use the buildin only for access to the admin backend.
Is there anything wrong with my reflections?
Is there anything wrong with my reflections?
Yes.
My current choice is wether to use the buildin User-Model or to build something my own.
There is a third choice.
http://docs.djangoproject.com/en/1.2/topics/auth/#storing-additional-information-about-users
everything else would be placed in a UserProfile
Correct.
build my one User Model and use the buildin only for access to the admin backend
Don't build your own.
Do this:
If you'd like to store additional
information related to your users,
Django provides a method to specify a
site-specific related model -- termed
a "user profile" -- for this purpose.
As the author of django-primate I would like to add some comments. Django-primate which easily lets ju modify the built in User model is meant for just that. You might need just something a little extra, then use django-primate.
But there are problems, although I do not think modifying the django User model per se is a problem at all. One problem is that the "users" are quite different, the admin user and some other user are often not related. This can cause problems when for example an admin is logged in and then wants to login to the site as a "normal user", they do not expect those accounts to be related and do not expect to be logged in automatically as the admin user. This causes headaches for no reason. It also causes a lot of other headaches to implement the recommended related Profile model, you often need to make sure there is a contrib user for every profile and a profile for every contrib user if you for example want to use the authentication decorators. Forms and administration of "users" make this even more cumbersome. In short: usually something will go wrong in this process at some point, it's a curse.
I have mostly abandoned the contrib User model for anything else but for admins. Building another user model is really what you want, but you also want the authenicating part for that user, hence the common use of django contrib User (using it for the wrong reasons). The best solution if you are in a situation like this is to build your own authenication for that custom user model. This is actually quite easy and I cannot recommend this approach enough. I think that the official recommendation is wrong and that there should instead be good tools for authenticating custom user models built into django.
You might want to have a look at the recently created django-primate: https://github.com/aino/django-primate
I once built a custom user model, inheriting from the default one. It works, however, I wouldn't recommend it.
Currently, you have some requirements, but over time they may change. Django's user system is quite straightforward, and using it allows to adapt more easily to some of the most common use cases.
Another aspect to think about, is that there are several applications already available that you can use, and that may require Django's users. Using your own model, may make usage of such modules much more difficult.
On the other hand, hacking the Django's user system in order to comply with your current requirements may be tricky.
Moreover, migrating a 'Custom-User' to a 'Django-User' is always possible, so you are not really closing that door.
Overall, I think it really depends on what you mean with 'user'.
If you mean just a registration, and no real interaction with the core Django features, then I think a separate model is enough, especially because you can migrate at any time, with relatively little effort.
However, if for your application a 'user' maps to something very similar to the what Django is for, then I would use the Django User-Model.
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.