Left Join in Django Model Multi-table Inheritance in Admin app - django

Scenario:
Let's say I want to extend Django's User model using multi-table inheritance. Let's say the model I created for that is called CustomUser.
Now let's assume that there are already existing records in the database corresponding to the User model and the table corresponding to the CustomUser model is still empty.
Now I want CustomUser model to be accessible from the Django's Admin app. What I noticed is only User model records which has a corresponding record in the CustomUser table is included in the change list of CustomUser, as if an INNER JOIN is being done behind the scene in the query... (I checked using connection.queries and it was indeed an INNER JOIN).
Now I want to change this behaviour so that a LEFT JOIN is done to retrieve records pertaining to CustomerUser.
How can I achieve this in Django?
Thank you very much!

Put below in any working admin.py.
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
#### below imports your custom user model
from accounts.models import CustomUser
admin.site.unregister(User)
class UserProfileInline(admin.StackedInline):
model = CustomUser
class UserProfileAdmin(UserAdmin):
inlines = [ UserProfileInline, ]
admin.site.register(User, UserProfileAdmin)
Above will show your CustomUser model in User in admin. now you can access User fields from UserProfileAdmin by User__first_name etc. pardon for bad english.

Related

Django: 'no such table' after extending the User model using OneToOneField

(Django 1.10.) I'm trying to follow this advice on extending the user model using OneToOneField. In my app 'polls' (yes, I'm extending the app made in the 'official' tutorial) I want to store two additional pieces of information about each user, namely, a string of characters and a number.
In my models.py I now have the following:
from django.contrib.auth.models import User
class Employee(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
stopien = models.CharField(max_length=100)
pensum = models.IntegerField()
and in admin.py the following:
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.models import User
from polls.models import Employee
class EmployeeInline(admin.StackedInline):
model = Employee
can_delete = False
verbose_name_plural = 'employee'
class UserAdmin(BaseUserAdmin):
inlines = (EmployeeInline, )
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
When adding a user using the admin panel my two new fields display correctly. However, when I click 'save', or if I don't add any user and just click on the name of my sole admin user in the admin panel, I get the following error:
OperationalError at /admin/auth/user/1/change/
no such table: polls_employee
I see some questions and answers related to similar problems, but they seem to be relevant for older version of Django. Could anyone give me a tip as to what I should do? Ideally I'd want my two additional fields display in the admin panel, though I suspect this might be a task for the future.
I have to confess I do not understand this paragraph from the documentation just following the advice I'm using:
These profile models are not special in any way - they are just Django models that happen to have a one-to-one link with a User model. As such, they do not get auto created when a user is created, but a django.db.models.signals.post_save could be used to create or update related models as appropriate.
Do I need to tie this 'post-save' to some element of the admin panel?
I'd be very greatful for any help!
You need run makemigrations to create a migration for your new model, and then migrate to run the migration and create the database table.
./manage.py makemigrations
./manage.py migrate

Django Admin Interface: Extend the 'groups' page show its users and allow adding new users

In the default admin interface, the group page is not very comprehensive. (attached a picture) I can't see the users that are part of that group, and I can't add any users from there (I have to go to the user's profile, and add them to the group one by one)
I tried to extend this functionality this from admin.py, but not sure how to do it. If auth_group, auth_user and auth_user_groups were user defined models in models.py, I'd probably do something like this:
from django.contrib import admin
from myproject.models import Group, User, GroupUserMembership
class MembershipInline(admin.TabularInline):
model = GroupUserMembership
extra = 1
class UserAdmin(admin.ModelAdmin):
inlines = (MembershipInline,)
class GroupAdmin(admin.ModelAdmin):
inlines = (MembershipInline,)
admin.site.register(Group, GroupAdmin)
admin.site.register(User, UserAdmin)
But this would result in
Exception Value: The model Group is already registered
(also I don't know how can I import auth_user_groups)
TL;DR How do I extend the Django Admin Interface to display the many-to-many relationship between the default auth models User and Groups? (like Permissions in the picture below)
You must first unregister the default User(model name) model admin before registering your own.
Try this
admin.site.unregister(User)
admin.site.register(User, UserAdmin)

how to register manytomanyfield in admin in django?

My model looks like this:
class Search(models.Model):
user = models.ForeignKey(User)
regions = models.ManyToManyField(Region)
class Region(models.Model):
name = models.CharField(max_length=100")
In my admin when I register Search model and Region model,
I want to see the User data in the Search model and search and user data in Region model.
both in the list_display and inlines of the admin. Since one is a ForeignKey and one is ManytoManyField, I am not clear how to get this working.
some help will be much appreciated
Thanks
You aren't going to be able to get the User data visible on the inline on the Region admin screen easily. Below is a decent starting spot.
from django.contrib import admin
from django.contrib.auth.models import User
from .models import Search, Region
class UserInline(admin.TabularInline):
model = User
class SearchAdmin(admin.ModelAdmin):
inlines = [
UserInline,
]
class SearchInline(admin.TabularInline):
model = Search
class SearchRegionsInline(admin.TabularInline):
model = Search.regions.through
class RegionAdmin(admin.ModelAdmin):
inlines = [
SearchRegionsInline,
SearchInline,
]
If you're set on editing the user information from the Region admin screen, then you will want to create a custom form for the SearchInline so it has the fields from the User model and then populate the values in the __init__ if an instance is passed in.

Django Filtering Admin Dropdowns

It seems this questions has been answered many times, but I am new to Django and apparently missing something when I try to work through the answers I have been finding. I have 2 Models, Model A is the main one and has a foreign key to Model B. When I make a new Model A in the Django Admin, I want the drop down for picking a Model B to only show the Model B's that have not already been assigned to a Model A. Can anyone point the right way?
You need to provide a custom form to the admin, telling it to only show a certain queryset for the Model B field:
from django import forms
from django.contrib import admin
from myapp.models import Person
class ModelAForm(forms.ModelForm):
model_b = ModelChoiceField(
queryset=ModelB.objects.exclude(model_a__isnull=False))
class Meta:
model = ModelA
class ModelAAdmin(admin.ModelAdmin):
form = ModelAForm

Django admin - stackedInline single instance

I'm building a site based on a highly customized django admin instance and am running into issues with user profiles as an inline to user_admin
long story short regardless of what I set for max_num and extra in the admin.StackedInline instance it allows up to 2 profiles per user - with a blank one in place by default if the user has an existing profile
anyone know how I could adjust this to show only a single inline profile without resorting to some JS front end hack?
relevant code from: profiles.admin.py
from django.contrib import admin
from django.contrib.auth.models import User
from django.contrib.auth.admin import UserAdmin
from profile.models import user_profile
class user_profile_admin(admin.StackedInline):
model = user_profile
fk_name = 'user'
max_num = 1
extra = 0
class user_admin_extended(UserAdmin):
inlines = [user_profile_admin, ]
admin.site.unregister(User)
admin.site.register(User, user_admin_extended)
I assume you're using FK field to connect user and profile? Try OneToOneField it should render just one inline in admin.