Additional auth tables when extending Djangos AbstractUser - python

I am new to Django and discovered something I do not quite understand: I extended the default user class of django auth with a custom field to look like this:
class User(AbstractUser):
business_entity = models.ForeignKey('BusinessEntity', on_delete=models.PROTECT)
In the settings file, I also added the needed AUTH_USER_MODEL = 'core.User' since my new user model is located in the core app. Works fine so far.
After applying all migrations (even after wiping the database and reapplying), I, however, am left with a few additional tables that I did not want to create and that seem not to be used by Django's auth app:
Tables created after migration
As you can see there are from the auth app: auth_group, auth_group_permissions and auth_permissions as well as from core app: core_user_groups, core_user_user_permissions.
I searched quite a while - maybe with the wrong keywords? - but I am not able to figure out if I need all those tables and - especially - what the additional core tables are used for. Can you shed some light on this?
Thank you very much!

I am quite sure those are the tables that django uses to store permissions and you shouldn't delete them. For instance, when you make a superuser (an admin), django knows that only he/she can access the /admin page. This knowledge comes from permissions stored in those tables.
If you are not using those tables chances are they only occupy a minimum amount of space (according to the link below, only 4 permissions are added by default) and you shouldn't worry about them. That said, knowing how to manage permissions well can help a lot depending on your project.
More info about permissions can be seen here.

Related

Django create custome admin view with non database fields

I would like to create a custome admin view with fields with data that I fill manually, meaning that there's no database table behind.
In my admin.py I have this so far
class TestAdmin(admin.ModelAdmin):
pass
admin.site.register(Test, TestAdmin)
and in the models.py
class Test(models.Model):
test = models.BooleanField(
default=True
)
But with this I receive an error
django.db.utils.ProgrammingError: relation "..._test" does not exist
Django is looking up the table in the database but in my model I need only fields which data I fill manually
It seems that you don't really get what a Model and ModelAdmin are. A Model class is the representation of a database table, and a ModelAdmin is a component that provides administration features for this table and it's content. IOW, when you write that "there's no database table behind", you're missing the point somehow: you cannot have a ModelAdmin without a Model, and you cannot have a Model without a database table.
To make a long story short: you'll either have to
1/ use a model or
2/ write the whole view(s) and templates by yourself and plug them into the admin.
For the second solution, see this question (and it's answers), or just google for "django admin views without models" (there are a couple 3rd part apps that are supposed to help plugin custom views in the admin).
Now the first solution might - or not, depending on your exact needs - be as good as the second one, depending on who populates your s3bucket and how. Without a model, you'll have to query the bucket for a file listing each and every time someone accesses your custom admin view, which might get quite costly. If all the uploads to the s3 bucket are under your control, you can use a model to keep a local file listing "cache" and you'll only need to hit s3 when effectively downloading a file. This also gives you the opportunity to store metadata about those files - which can be used for searching / filtering - and eventually to link your s3 files to other models if needed. And of course this means you get your admin for free ;)
Actually even if you don't have control on those uploads, you may still want to use a model for the above reasons and have a background task (cron job or equivalent) that updatees your table from the s3 bucket contents (or - if s3 provides web hooks - have an API endpoint called by s3 on uploads that updates your table).
The way that django's ORM works is that all class members of a model class that is an instance of model.Field will map to a column in the database.
It is possible to have model properties that does not map to a database table. You could use a #property instead, for example.
class Test(models.Model):
#property
def test(self):
return get_aws_bucket_value(self.id)
#test.setter
def test(self, value):
set_aws_bucket_value(self.id, value)
You have to implement the aws getter/setter functions yourself.
You can use properties as read-only fields in the django admin class. Be careful about using it in the list view if your getter logic needs to fetch data from a remote server syncronously, since that would be a significant performance bottleneck.
If you want to be able to set values for a setter from the django admin, you would have to write a custom ModelForm for TestAdmin.
It is possible to wrangle Django into doing what you want here. But Django's models and admin are based around the ORM, which means using a relational database as persistant storage. If you don't want that, you can find yourself fighting against and overriding the framework more often than benefiting from Django's "batteries included". This project might be better solved with a less monolithic and less opinionated framework such as Flask instead of Django.

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.

Whether to define own User model in django or use Django auth user model?

I am starting with Django App schema design and my schema has UserProfile, UserFavourites and UserComments models .
After doing a bit research i found out that we can user django's own User model or we can create own user model which will extend from AbstractUser
Platform = Django 1.8.5
I have found many similar questions but now that i have newest version of Django framework has anything changed ?
Also need to know pros and cons of each approach
In a new project, strongly consider starting out with a custom User model.
The reason is that if you want to change your User model later, then there is a clear way to do that (migrations). However, switching from a auth-User to a custom User when you already have ForeignKey relations (etc) to the auth-User is a major pain (see below). Considering that it is very easy to just start out with your own model at the start of a project (maybe just copy the auth model), there is very little reason not to.
The docs say this about how hard it is to change AUTH_USER_MODEL later:
Warning
Changing AUTH_USER_MODEL has a big effect on your database structure.
It changes the tables that are available, and it will affect the
construction of foreign keys and many-to-many relationships. If you
intend to set AUTH_USER_MODEL, you should set it before creating any
migrations or running manage.py migrate for the first time.
Changing this setting after you have tables created is not supported
by makemigrations and will result in you having to manually fix your
schema, port your data from the old user table, and possibly manually
reapply some migrations.
Warning
Due to limitations of Django’s dynamic dependency feature for
swappable models, you must ensure that the model referenced by
AUTH_USER_MODEL is created in the first migration of its app (usually
called 0001_initial); otherwise, you will have dependency issues.
In addition, you may run into a CircularDependencyError when running
your migrations as Django won’t be able to automatically break the
dependency loop due to the dynamic dependency. If you see this error,
you should break the loop by moving the models depended on by your
User model into a second migration (you can try making two normal
models that have a ForeignKey to each other and seeing how
makemigrations resolves that circular dependency if you want to see
how it’s usually done)
In other words, if you choose not to use AUTH_USER_MODEL at the start of your project, it's almost impossible to change later.
There is a ticket #24370 for adding custom user model and AUTH_USER_MODEL setting to the default project template, and to recommend doing this in the documentation. This ticket is just waiting for someone to implement it.
Pulled from Django's documentation
If you wish to store information related to User, you can use a one-to-one relationship to a model containing the fields for additional information. This one-to-one model is often called a profile model, as it might store non-auth related information about a site user
So just add your extra user fields to UserProfile Model. Make a one-to-one relationship with each of your desired model

Django add two fields to user profile

I am trying to add two additional profile fields and have the native authentication work like normal.
I am trying to fallow the documentation here
and the SO here
In my settings file
#settings.py
AUTH_USER_MODEL = 'users.User'
in my users.user model
#users/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
foo = models.CharField(max_length=32, default='Blue')
bar = models.CharField(max_length=32, default='Blue')
print "user.user"
i have created 3 superusers non can log into admin. i have tried syncing the DB after adding a user. i have tried restating the dev server between adding a user.
the only time i see the output of print "user.user" is when i run the createsuperuser command.
i think i cant log in because the user is not really being created. it runs my User class and then skips actually creating the user. but i am kinda new to this so i could be way off and way out of my league.
why cant i log in and how do i add the two fields?
Have you read the warning in Django's documentation?
Changing AUTH_USER_MODEL has a big effect on your database structure. It changes the tables that are available, and it will affect the construction of foreign keys and many-to-many relationships. If you intend to set AUTH_USER_MODEL, you should set it before running manage.py syncdb for the first time.
If you have an existing project and you want to migrate to using a custom User model, you may need to look into using a migration tool like South to ease the transition.
Given this warning, are you working on a fresh database, or are you migrating using South? If you have an existing database and made these changes, then simply running syncdb will most likely no be sufficient.
If this is a development server without any important data, I would recreate your database, and then run ./manage.py syncdb. If you are using a SQLite database, then you can simply copy it to somewhere else (if you would like to keep the data), and run syncdb again to create a new database.
Here is the relevant documentation.
It would also be helpful to know exactly what error you are receiving. Do you attempt to login and admin tells you that your user/pass combination is not correct, or is there an actual error thrown? Your question doesn't quite make this clear.

Do I need to create a separate class in my models.py when using the django.contrib.auth.models import user?

The import statement import the needed parts. but is the "user" class already made when you put that into your installed apps? or do you still need to clarify in models.py in order to make the table in the db? or can someone expand on how to use django users and sessions? I'm looking over the django docs right now and they all just go over how to use the thing once. they never put the code in a syntax where users are going to be the ones using the code through a browser and not you through a python shell.
All installed apps can contribute to the database schema. django.contrib.auth.models contributes, among others, the auth_user table behind the django.contrib.auth.models.User model, therefore you do not have to worry about recreating it unless you have a specific reason to do so.
There's a number of things going on here. As you're aware, Django comes with a number of "contrib" packages that can be used in your app. You "activate" these by putting them into your INSTALLED_APPS.
When you run python manage.py syncdb, Django parse the models.py files of every app in INSTALLED_APPS and creates the associated tables in your database. So, once you have added django.contrib.auth to your INSTALLED_APPS and ran syncdb, the tables for User and Group are there and ready to be used.
Now, if you want to use these models in your other apps, you can import them, as you mention, with something like from django.contrib.auth.models import User. You can then do something like create a ForeignKey, OneToOneField or ManyToManyField on one of your models to the User model. When you do this, no tables are created (with the exception of ManyToManyField; more on that in a bit). The same table is always used for User, just as for any of your own models that you might create relationships between.
ManyToManyFields are slightly different in that an intermediary table is created (often called a "join table") that links both sides of the relationship together. However, this is purely for the purposes of that one particular relationship -- nothing about the actual User table is different or changed in any way.
The point is that one table is created for User and this same table is used to store all Users no matter what context they were created in. You can import User into any and all of your apps, create as many and as varied relationships as you like and nothing really changes as far as User is concerned.
If the table name or something else does not fit in your needs you can always just extend the User model.
from django.contrib.auth.models import User
class Employee(User):
...
Any class extending Model class in models.py contributes to database schema. That means, django search your (and also django core) model.py files and looks for any class that extends Model like:
some models.py
class SomeModel(Model):
...
...
class Otherthing(Model):
...
that is also applies for django core code files. Since all Database tables named using application label and model name, database ables created by django also have that...
For example,
from django.contrib.auth.models import User
If you track file hierarchy django -> contrib -> auth and open models.py file, you will see related model. Ther are also other Model classes in here, like Permission and Group models.
Since these models are under auth application, database tables are auth_user, auth_perission and auth_group
When you run manage.py syncdb command for the first time, django will create these tables...

Categories

Resources