Django DRF Djoser - change default User model to custom model which is not equal but inherited from AUTH_USER_MODEL - django

In django have the following custom user structure:
class CinemaUser(AbstractUser): ...
class CinemaAdmin(CinemaUser):....
class Cinemagoer(CinemaUser): ...
Logic is that I have
Cinemagoer - an ordinary user (can register themselves),
CinemaAdmin - kind of administrator (is created only by superuser) and
Superuser.
in settings: AUTH_USER_MODEL = CinemaUser
the problem is with Djoser,
a request http://localhost:8000/auth/users/ (with data in body) creates CinemaUser, because Djoser has User = get_user_model(), which means Djoser uses AUTH_USER_MODE, while I need Djoser to use Cinemagoer model to create Cinemagoer). How can I use Cinemagoer with Djoser in this case?
I tried to change in Djoser/serializers directly User = CinemaUser ... just for test, it works fine, but it is definitely the wrong way.

Related

Django admin: created users have plain text password and can't login

I want to have a custom tab for staff users so in admin.py I do:
class StaffUser(User):
class Meta:
proxy = True
#admin.register(StaffUser)
class AdminUserAdmin(admin.ModelAdmin):
pass
But on the admin site, whenever I add a new user with this interface I can't log in with it since for some reason it sets it's password as plain text instead of hashing it.
I've read this post BUT if I do that and change StaffUser to inherint from AdminUserI get this other error
AttributeError: type object 'StaffUser' has no attribute '_meta'
You should declare your models in models.py (or a models package), not admin.py.
UserAdmin (there is no such thing as an AdminUser in the Django packages) is a subclass of ModelAdmin, that is, a class for registering models in the Django admin. It is not a model subclass that you can extend to make new models.
Also, if you are trying to extend the User just to distinguish users with access to the Django admin site, note that there is already an is_staff property in the default User model. And in any case, if you still want to extend the User model, you should be extending AbstractUser instead as stated in the docs.

The relation between a model and it's form in Django, and user authentication

I'm migrating something from an old PHP/apache server to Django. I'm a bit stumped with the 'ModelForm'.
As far as I understand, a "Model" is the abstraction for persistent elements in my website/server - specifically this is something stored physically, say in a database, and defines the fields (read columns) in the DB.
I started moving the authentication part of the site, and discovered models, and specifically the User model (I made an empty User inheriting AbstractUser just in case I will ever need to extend things). Now I want to create a simple two field form, to authenticate login.
The form:
Username (which is a field of User, by default)
Password (Which is not).
Even the 'Username' needs a redefinition in the model form. So my questions:
What is the advantage of the model form (over just a form)? - seems like you're redefining fields anyway, and obviously sometimes adding fields on top of the model.
Specifically for authentication, I probably need to store my salted hash associated with the user somehow, compare my password using that and retrieve the user object. This is something I find very hard to find in the Django docs - they just have too much written on authentication, and not one full code example. Do I put this in the "validate" method of form, retrieving there an object and storing it in a session or something?
If there is a deeper relation between a model form and the associated model, I would like to know as well.
Simple django forms and modelforms have quite differences.
class ArticleForm(ModelForm):
class Meta:
model = Article
fields = ['pub_date', 'headline', 'content', 'reporter']
The above example illustrates that you don't have to write any form field in here. The model form will itself create a form which is based on the attributes provided in the model ('Article' in this example).
If you create a simple django form then it would be something like:
class ArticleForm(forms.Form):
some_field = forms.CharField(some_attrs)
...
The django User model provides you everything you need for authentication. When you want to create users just import django.contrib.auth.models.User and use create method to create objects. Then when you want to authenticate a user use authenticate method.
from django.contrib.auth import authenticate, login
def user_login(request):
username = request.POST.get('username')
password = request.POST.get('password')
user = authenticate(request, username=username, password=password)
# after authentication login the user or set cookies or modify the session or some other action can be taken
return HttpResponse("Some response or use render for html page")
username and password will be coming from your post request.
If you want to extend default Django user model you can use django user model as onetoonefield in your extended model.
class AppUser(models.Model):
user = models.OneToOneField(User)
... # other custom fields

Separate AUTH_USER_MODEL for Django Rest Framework

The Django-Project contains a REST-API, based on TokenAuthentication and a Web Login to the Backend with the Django Auth User.
The Problem is: I found no way to specify two different AUTH_USER_MODEL'S for each authentication individually.
For the REST-API users, I defined a Custom User Model:
class User(models.Model):
id = models.IntegerField(primary_key=True)
name = ....
....
USERNAME_FIELD = 'id'
REQUIRED_FIELDS = []
In the settings I added AUTH_USER_MODEL = 'backend.User', so that the rest_framework Token authentication references to the right user model.
But when enabling the django.contrib.auth.views.login for the Web-Backend, this also uses the backend.Usermodel for authentication. But it should use the django built in user model.
How can I specify a second user model specifically for either the rest framework api or for the django.contrib.auth.views?

Adding Password Requirements to Django's Admin Interface

The "Overview" section of the "User authentication in Django" documentation says that the authentication system in Django doesn't provide password strength checking. I wrote a form class that adds some basic password requirements such as minimum character length. I'm trying to implement it in Django's admin interface. As far as I know, there are three places I will need to implement my password requirements:
Creating a user: /admin/auth/user/add/
Changing a user's password: /admin/auth/user/1/password/
Changing my own password: /admin/password_change/
I can take care of the first two by subclassing UserAdmin and specifying add_form and change_password_form:
https://github.com/django/django/blob/1.8.2/django/contrib/auth/admin.py#L58-L59
How can I get the third one (changing my own password) to use my password requirements? The code is a little above me:
https://github.com/django/django/blob/1.8.2/django/contrib/admin/sites.py#L314
Obviously by sub-classing and using your own AdminSite
# my_admin.py
class MyAdminSite(AdminSite):
def password_change(self, request, extra_context=None):
...
site = MyAdminSite()
You can disable autodiscovery for default admin site, by using AdminConfig for INSTALLED_APPS settings (django 1.8+ only)
INSTALLED_APPS = (
'django.contrib.admin.apps.AdminConfig',
...
)
And then you have to manually register required models to your new admin site.

django - Extending `auth.models.User` and usering login, logout

If I create a CustomUser model which inherits from django.contrib.auth.models.User, like so:
in models.py
class CustomUser(django.contrib.auth.models.User):
customfield = TextField()
...
Should I still be able to use
django.contrib.auth.{authenticate, login, logout} in the normal way? Do I have to make some additional configuration change? I know these methods only work on User objects, but technically my CustomUser is-a User.
Currently, authenticate(username=u, password=p) is always returning None, even with valid credentials.
Since Django 1.5 (officially but it doesn't worked for me) and "stable" in 1.6 there is a functionality to extend the User model in a clean way.
At first:
-> Take care that you load the User model only via:
from django.contrib.auth import get_user_model
User = get_user_model()
-> Once you have built the database theres no easy way to change the User model. The database relations will break and Django / South isn't able to fix it.
-> third party modules have to be compatible with that new layout and refer in it's models to "get_user_model()", too.
You have to add some Code for the admin to respect your new model:
See: https://docs.djangoproject.com/en/dev/topics/auth/customizing/#extending-the-existing-user-model
To Override the model you need to inherit from AbstractBaseUser:
from django.contrib.auth.models import AbstractBaseUser
class MyUser(AbstractBaseUser):
...
date_of_birth = models.DateField()
height = models.FloatField()
...
REQUIRED_FIELDS = ['date_of_birth', 'height']
AbstractBaseUser provides you all attributes of the default user model. So you don't have to take care of email, username, first_name, last_name, password etc.
More info about overriding the user model: https://docs.djangoproject.com/en/dev/topics/auth/customizing/#django.contrib.auth.models.CustomUser
In your settings link your new model:
AUTH_USER_MODEL = 'customauth.MyUser'
Please read the whole documentation of customizing the user model, there are some interesting hints for overriding the default manager, admin forms etc. Just remember that bigger changes in an existing project can be a big pain.
A short overview:
- Extend models.AbstractUser
- Set AUTH_USER_MODEL in settings.py
All details can be found here: https://docs.djangoproject.com/en/dev/topics/auth/customizing/#specifying-a-custom-user-model