Why not to extend User in Django REST - python

I am using Django REST to create users for my app.
Everywhere i look at, for users they extend AbstractBaseUser.
I tried extending the User model, and it seems to work just fine.
I have an PersonalAbstractUser that extends the Django User. Then, Worker and Client extends PersonalAbstractUser.
Login and custom permissions seem to work just fine up until now, but i am getting concerned when i see that no one else is extending User...
Why is that? Did i miss something?

This is not a question about Django REST, but about Django itself.
The problem with extending the User object directly is that it is already a concrete model, so extending it will use multi-table inheritance. That's not usually a good idea - especially if you're further extending it.
AbstractUser is an abstract model, but (unlike AbatractBaseUser) contains all the fields that User defines. You should use that.

Related

Extend User Model or Custom Pipeline in Social-App-Django

I am implementing social-app-django (not the deprecated one; the one that relies on Python-social-auth) with django 1.11 (not using Mongo). My application will need to store and manipulate a lot of data on users other than that which is fetched from their social media accounts at login.
I don't need to fetch or collect any extra data when the user authenticates, but various actions they perform on my site will need to be saved to their user model. I am wondering which of the following approaches is preferred (I've searched extensively online, but can't find a specific explanation of why to use one vs the other):
Create my own user model in my app's models.py (call it MyUser) that doesn't extend anything special, and then add a function in the authentication pipeline that associates the social-app-django user with a corresponding instance of MyUser. Leave AUTH_USER_MODEL and SOCIAL_AUTH_USER_MODEL unchanged.
or...
Create my own user model in my app's models.py, and in the project's settings.py set AUTH_USER_MODEL and SOCIAL_AUTH_USER_MODEL to point to MyUser. Leave the pipeline unchanged. In this case, I was wondering whether someone could clarify what MyUser and its manager should extend, and what I need to import in modules.py (I am confused because a lot of stack overflow posts are referring to deprecated versions of this module and I keep getting errors). Also, in this case should I be setting both AUTH_USER_MODEL and SOCIAL_AUTH_USER_MODEL, or just one of them?
Do these two methods essentially achieve the same thing? Is one more reliable/preferred for some reason? Or, should I be doing both? Thanks very much for any assistance.
Another detail: I would like to be able to access the User database not only from the app I am currently building, but also from other apps (within the same Django project) that I will build in the future. Does this affect anything?
Since I see this has a decent number of views I will post the solution I eventually came to.
Both django and social-app-django (or any other social auth module) make use of the default User model for authentication. While it's possible to edit this model to add custom parameters, I don't recommend it. It's not good abstraction or modularization. If you make a mistake when configuring the model, you won't just break a specific feature on your site, but you might also break the authentication itself.
The only circumstances I can think of under which you'd want to edit the default user model itself is if you need to make changes that affect the authentication flow itself (for example, adding your own custom authentication provider).
It's much easier and safer to create a new model called UserProfile, with a required one-to-one relationship to a User object. Now, you can treat the User object as the authentication part, and the UserProfile object as the content/storage part. You won't have to mess with the User model very often, and the UserProfile model doesn't matter for authentication purposes. Note that in this configuration you should NOT need to change the AUTH_USER_MODEL or SOCIAL_AUTH_USER_MODEL fields in the settings.py file.
If you take this approach, you will need to add a custom step in the authentication pipeline in which you create a new UserProfile object and associate it with the User who is currently logging in.

Adding a Non-Model Form in Django Admin

I am trying to add a non-model form in django admin interface and am not able to find any particular way to do it. This form would do some processing and change some data in the DB. But this is not related to a particular Model and should stand out. This form should not be available for the user to use.
One thing I can do is add the form to the general view and prohibit using permissions but I was thinking since django admin interface already exists, it would be better to add that to the django admin interface.
Is this possible to do in Django?
You can add arbitrary views that within a ModelAdmin that do whatever you want. See the documentation for ModelAdmin.get_urls. You can do the same at a higher level by defining AdminSite.get_urls.

Django: extending user model vs creating user profile model

I'm creating an app in Django and so far I have been using an extended user model like so:
class MyUser(AbstractBaseUser):
...
with all the user and profile info, but I see a lot of people creating different models for the profile and the user itself on stack overflow, using OneToOneField, although those are mostly old questions.
My question is: which is better and, if there isn't a best among them, what are the advantages for each solution?
thanks!
It depends on what you want to do -- if you're happy with the User model as it stands in the latest version of Django you should just use that -- it's easy and you'll get a lot functionality that goes along with it -- for example a pretty good permission system, and you can be sure to be compatible with all third party modules. But if you thing you'll need to expand on the User model, it's pretty straightforward how to do it. You might find that in the future you need to add more methods to your model than you expected.
The examples that you see with separate UserProfile / User model are mostly a legacy of django < 1.5, where that was the recommended way to extend the User model. There's no reason to follow that pattern any more -- it's a lot more work to have to use two models where you just want one model
**2019 Update**
If you are starting a new Django project, you should always create your own custom user model that inherits from AbstractUser, as per the Django documentation, i.e.
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
pass
even if you don't need any additional functionality. The reason for this is that for very low effort, you are making it easy to customize your user object in the future. It's very laborious to replace the built-in User object with your own after you have run the initial migrations, unless you're able to delete all of your data and migrations and start over.
I find some useful information in Django docs:
Extending Django’s default User¶
If you’re entirely happy with Django’s User model and you just want to
add some additional profile information, you could simply subclass
django.contrib.auth.models.AbstractUser and add your custom profile
fields, although we’d recommend a separate model as described in the
“Model design considerations” note of Specifying a custom User model.
AbstractUser provides the full implementation of the default User as
an abstract model.
And:
Model design considerations
Think carefully before handling information not directly related to
authentication in your custom User Model.
It may be better to store app-specific user information in a model
that has a relation with the User model. That allows each app to
specify its own user data requirements without risking conflicts with
other apps. On the other hand, queries to retrieve this related
information will involve a database join, which may have an effect on
performance.
So if I reads it correctly, it means if the fields are related to authentication, then you should consider substitute the original User model. But if it's not related, like profile fields, such birthday, or profile_image, then you might want to create a standalone app that reference the original User model.
And a good tutorial I found: http://riceball.com/d/content/django-18-tutoria-52-adding-user-profile
A ForeignKey is to create a one-to-many relationship. In other words, it will return a queryset. For example, a single car has many wheels, but one wheel isn't attached to several different cars.
A OneToOneField will create a relationship between strictly two objects. For example, the rim belongs to the front-left tire, and only that tire has that rim.
Does that make sense?

Django ModelAdmin not registered

First, I want to inform that I did check other related questions but their solutions were very simple (improper registration, settings, etc.). This problem is weird in a way that I haven't faced in 3+ years of developing with Django. So here comes:
I have an app that's 90% celery tasks, so it only has two models. They are simple. I have two ModelAdmin classes defined in the admin.py of the app, one for each model. These are simple as well. They are both registered properly. The app is in the INSTALLED_APPS.
All kosher and without any customization of templates, tags or forms, just a plain admin.py:
from myapp.models import (Something, OtherModel)
class SomethingAdmin(admin.ModelAdmin):
# admin config ...
class OtherModelAdmin(admin.ModelAdmin):
pass # Trying anything at this point...
admin.site.register(Something, SomethingAdmin)
admin.site.register(OtherModel, OtherModelAdmin)
So simple it cannot fail, but it does: one of them doesn't show up in the admin. It's simply not registered (404 on manual url access). The other one does show up, and does work properly.
Validation on that invisible admin works because when I add a strange value to its list_display, Django does raise the proper exception (ImproperlyConfigured). So it does reads it, it just fails to register it. If I comment the visible one out, the app is simply removed from the admin (of course, it thinks no modeladmins).
So, in short, one of the ModelAdmins is invisible, while the other one in the same file and with nearly identical configuration, isn't. Any thoughts?
EDIT: Answers to a few suggestions I expect: Yes, the model is working properly (and heavily unit tested), and I have created/saved instances and they are in the db. Yes, I did restart the server. Yes, the computer is plugged in and it's currently on. :)
As it turns out, the problem was in the structure: models was a package, instead of the more usual module. It seems that even if you make the model available at package level (import it in init.py), Django still doesn't know in what app it should be included.
What you need to do is specify the app_label in its Meta class. So the model now becomes:
from django.db import models
class OtherModel(models.Model):
class Meta:
app_label = 'someapp'
# other meta attrs
# Model attrs ...
Odd that it needs to be specified, when the model is available in the usual models.SomeModel namespace, but at least the solution's simple enough.
BTW, as you can guess the other model did include this Meta attr, I just didn't notice it before. LOL.

Country-based Super User Access, and modifiying Django Auth

I'm looking to give super user access to users of a program I'm devving.
All the entities have a country id value, so i'm just lookign to hook up my user model to have a country ID
Looking at Django Auth, It should be nice and easy to add a super_user_country_id field.
However, how frowned upon is it to modify the core django classes?
Is there any easier way to go about this or?
At the moment, the recommended way is to create a Profile model and link it to the User model with a OneToOneField or a ForeignKey (depending on your requirements). Here's a good tutorial on the topic.
The Django devs have repeatedly expressed their intent to make extending the User model more straightforward, but AFAIK, no concrete design has been proposed, yet.
Adding a custom UserProfile would be one way to go about this. UserProfile can link to Country and you can prevent users based on their UserProfile. I found James Bennett's article on extending the User model useful when I had a similar requirement.
It is generally not a good idea to patch auth (or other built in) classes. Custom patches can become a pain to maintain and keep up to date.

Categories

Resources