Why does django need a database for custom authentication backends? - django

I implemented a django custom authentication backend. My authenticate() returns a user object like this return User(username=username, password=password), but I never store the User object to a database.
Why do do the django docs recommend creating a database with user objects? (https://docs.djangoproject.com/en/1.4/topics/auth/#writing-an-authentication-backend - "...the best way to deal with this is to create a Django User object for each user that exists for your backend...")
If I try calling login(), there's a call made to the database. If logins are stored in sessions, why is a database necessary? (Using cached sessions)

The reason why you specifically need to save the User object is that it's common for apps to create database level relationships between objects and users (in order to persist the relationship across multiple requests).
A simple example would be the activity log in django.contrib.admin. It displays recent behaviour that users have performed. This only works when the user object is saved to the database.

Quite a few apps have a foreign key to auth.User; if you don't have that table populated then you don't get to use those apps.

Related

In a Django Rest Framework view, does request.user make a database call or the database call happens before the request reaches the view?

I need to retrieve some information about my users and I am trying to avoid making unnecessary database calls.
The information I need is stored in three models: User, UserProfile and Membership.
Both UserProfile and Membership have a OneToOne relationship with the User model.
I know that I can use select_related() to retrieve related models from the database in a single call. So I could do something like:
User.objects.select_related('userprofile').select_related('membership').get(id=request.user.id)
But that must not be correct, because if I am using some user information to do the query, it means I already retrieved this information in a previous call.
So what would be the best way to get this information minimising database calls? Would it be even possible to get the information from these 3 models in a single call?
DRF performs user related DB query inside authentication class. See source here. So if you need to optimize this query you should implement custom autentication class(see details here), override authenticate_credentials method and use optimized query inside it.

How to dynamically swap default database on the model manager in django?

I am creating a project in django and django rest framework. Its an api for an angular app. The database setup consists of multiple databases. one is default database, all the django tables reside in this database; rest of the databases belong to a type of a user, each user is supposed to have a separate database. So, all the user related data goes to its separate database. To implement the selecting database dynamically, user object has an extra field to store the database to write to.
from django.contrib.auth.models import AbstractUser
class CustomUser(AbstractUser):
"""Custom User model."""
database= models.CharField(max_length=9)
Reason for doing this was performance improvement as each database is separate, ListView and DetailView would work faster than if the data was stored in the one database only.
I know I can choose a database to store by using the using method on the model manager. In the rest api things work fine and data is being stored in their separate databases, but I end up overriding methods that django has defined. Its adding development cost to the project. Foreign keys and ManytoMany keys needs to be resolved with the current database of the user, which is not happening as I have customized the database setup. Also, my code cant be as good as theirs :p , as they have written django over the course of many years.
I have overwritten many querysets already, but django still uses default database many times. If only I could use the request object in the model manager of django models to swap the default database on per request basis, things would be different i think.
My questions are -
Is there a way to access the request object in the model manager? I could do something to the effect of below code.
class CustomManager(models.Manager):
def get_queryset(self, request):
return super(CustomManager, self).using(request.user.database).get_queryset()
Model manager has _db property that could be used to select database. Would overriding it is advised? if yes, how and where in the code?
Is there a better way to implement the separate databases?
Thanks in advance.
Regards
Using a database router is recommended in Django docs, but the problem is it only accesses the model class.
Found a couple of questions related to the problem of switching databases dynamically. This post has a solution that would solve the problem of passing the request.user or any other parameter by using a threading.local instance.
Someone created a reusable plugin even for this - https://github.com/ambitioninc/django-dynamic-db-router
Hope that helps.

django_auth_ldap vs postgres db using django models

I am creating an app where I store the USERS in a Postgres database with the help of the standard User Model, in my Django app i use Django queries to get all needed information, like "first_name", "username" .. etc
I implemented Django_auth_ldap to start storing user identification data in an Openldap server if i want. But now, i'm confused to how to get the data i used to get using django queries. i don't want to change the behavior in my views, i want to continue using Django queries
This looks like it describes some of what you want: https://django-auth-ldap.readthedocs.io/en/latest/users.html
You can perform arbitrary population of your user models by adding listeners to the Django signal: django_auth_ldap.backend.populate_user. This signal is sent after the user object has been constructed (but not necessarily saved) and any configured attribute mapping has been applied (see below). You can use this to propagate information from the LDAP directory to the user object any way you like. If you need the user object to exist in the database at this point, you can save it in your signal handler or override get_or_build_user(). In either case, the user instance will be saved automatically after the signal handlers are run.

Django app has multiple database and multiple user

I have written one Django cloud based app. This app will have multiple user and for them multiple database, so that their data should be separate and they can save only to same database.
1) How can we implement it
2) How to automatically one user from login page to assign the database to write on it.
I don't have a complete answer, since you do not give a lot of detail. But here are a couple ots that f hinDjango supports custom database router implementations. A database router is a class that helps django decide which database to use for a particular model. Unfortunately I don't think this mechanism is granular enough for your needs. You can also specify the database to use in your code by using using(name) queryset method and save(using=name) form of save() method for instances. Of course this also means that some features of Django are going to be unvailable to you, since you cannot always expect to have a user. Look at the docs here for more info
https://docs.djangoproject.com/en/dev/topics/db/multi-db/

Can i avoid the creation of the Django auth.model.User table when using "other authentication sources"?

As the Django documentation says about Other authentication sources, in order to authenticate against another source, you must implement your own authentication backend. Also, They explain that:
The Django admin system is tightly coupled to the Django User object described at the beginning of this document. For now, the best way to deal with this is to create a Django User object for each user that exists for your backend (e.g., in your LDAP directory, your external SQL database, etc.)
As i'm not going to use the admin system (i'm assuming they are referencing the admin application) can i avoid that table replication?
I was thinking of implementing the authenticate and get_user methods as the doc says but that implies the instantiation of the User class, so the next question would be: can the auth.models.User class be instantiated without having the actual Django User table?
The short answer to your question is - yes, it can. Simply set the managed property to False on the User model.
You should map the user from the external authentication into the auth.User object.
Remove django.contrib.auth from the INSTALLED_APPS setting.
Is there a particular reason you don't want the table to be created? If you write (or use a pre-existing) LDAP authentication backend, the User objects will be stored in the table, but they won't have any password information stored, and you can easily update fields like email address and name during the authentication process, so you won't create a disconnect between information stored in LDAP and managed in the Django table (i.e., you can continue updating auth information from LDAP, and don't have to worry about also updating it in the Django DB).
There's no way to avoid the table and still have any sort authentication. The "alternative" authentication methods still make use of the auth_user table, they just authenticate via another means.