Let's have 2 models that extends the user model called Ext1 and Ext2 declared as follow:
class ExtN(models.Model):
user = models.OneToOneField(User)
extra_param = models.xxxField()
then I declare in application specific admin.py file something like:
class ExtNInline(admin.StackedInline):
model = ExtN
can_delete = False
in which file do I need to put the following code, in order to see the form to edit both models related to the user?
class UserAdmin(UserAdmin):
inlines = (Ext1Inline, Ext2Inline, )
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
Thanks in advance.
You should put it in the same admin.py file
Extending the user model
Related
I have a Profiles app that has a model called profile, i use that model to extend the django built in user model without subclassing it.
models.py
class BaseProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, related_name='owner',primary_key=True)
supervisor = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='supervisor', null=True, blank=True)
#python_2_unicode_compatible
class Profile(BaseProfile):
def __str__(self):
return "{}'s profile". format(self.user)
admin.py
class UserProfileInline(admin.StackedInline):
model = Profile
class NewUserAdmin(NamedUserAdmin):
inlines = [UserProfileInline ]
admin.site.unregister(User)
admin.site.register(User, NewUserAdmin)
admin
the error is
<class 'profiles.admin.UserProfileInline'>: (admin.E202) 'profiles.Profile' has more than one ForeignKey to 'authtools.User'.
obviously i want to select a user to be a supervisor to another user. I think the relationship in the model is OK, the one that's complaining is admins.py file. Any idea ?
You need to use multiple inline admin.
When you have a model with multiple ForeignKeys to the same parent model, you'll need specify the fk_name attribute in your inline admin:
class UserProfileInline(admin.StackedInline):
model = Profile
fk_name = "user"
class SupervisorProfileInline(admin.StackedInline):
model = Profile
fk_name = "supervisor"
class NewUserAdmin(NamedUserAdmin):
inlines = [UserProfileInline, SupervisorProfileInline]
Django has some documentation on dealing with this: https://docs.djangoproject.com/en/1.9/ref/contrib/admin/#working-with-a-model-with-two-or-more-foreign-keys-to-the-same-parent-model
Here is an example that I have just tested to be working
class Task(models.Model):
owner = models.ForeignKey(User, related_name='task_owner')
assignee = models.ForeignKey(User, related_name='task_assigned_to')
In admin.py
class TaskInLine(admin.TabularInLine):
model = User
#admin.register(Task)
class MyModelAdmin(admin.ModelAdmin):
list_display = ['owner', 'assignee']
inlines = [TaskInLine]
I would like to add some extra fields to user in django-cms (in django admin panel). How to do this in the simplest way?
Need to add two fields user bio and image. And can i use this in frontend to show a page with all the user info?
From the django docs
Create you custom user model like this
from django.contrib.auth.models import User
class Employee(models.Model):
user = models.OneToOneField(User)
department = models.CharField(max_length=100)
Change the admin file like this
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from my_user_profile_app.models import Employee
# Define an inline admin descriptor for Employee model
# which acts a bit like a singleton
class EmployeeInline(admin.StackedInline):
model = Employee
can_delete = False
verbose_name_plural = 'employee'
# Define a new User admin
class UserAdmin(UserAdmin):
inlines = (EmployeeInline, )
# Re-register UserAdmin
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
OR
Another option is to define a custom user model. For more details please visit https://docs.djangoproject.com/en/1.8/topics/auth/customizing/#a-full-example
Taken from Django documentation:
The simplest way would be to create what is often called a profile model. So for your example you would create something like
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.OneToOneField(User)
bio = models.TextField()
image = models.ImageField()
Then, for seeing this in the admin panel, you would reregister admin for the User
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from my_user_profile_app.models import Profile
class UserProfileInline(admin.StackedInline):
model = Profile
can_delete = False
verbose_name_plural = 'profile'
# Define a new User admin
class UserAdmin(UserAdmin):
inlines = (UserProfileInline, )
# Re-register UserAdmin
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
As far as showing this in frontend, you can use User as well as Profile the same way you would use other Django models.
Is it possible to move default Groups model from 'Authentication and Authoriation' section (on the Django admin site) to custom one and how to achieve that?
Let's start from the beginning in the other words.
I have a very simple application 'accounts' in my Django project.
models.py file looks like below:
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
def __str__(self):
return self.email
serializers.py file:
from rest_framework import serializers
from django.contrib.auth.models import Group
from django.contrib.auth import get_user_model
class GroupSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Group
class UserSerializer(serializers.HyperlinkedModelSerializer):
groups = serializers.HyperlinkedRelatedField(
many=True,
required=False,
read_only=True,
view_name="group-detail"
)
class Meta:
model = get_user_model()
exclude = ('user_permissions',)
Now, on the admin site I have two sections: 'Accounts' and 'Authentication and Authorization'. 'Accounts' section contains my 'Users' table (for User model) and 'Authentication and Authorization' section contains 'Groups' table (for Django's default authorization Group model).
My question is - is it possible and how to move Groups table (model) to the 'Accounts' section?
I've even tried to create a custom 'Group' model based on Django's default auth Group model but have stuck on migration exceptions.
Is it possible to move default Groups model from 'Authentication and Authoriation' section (on the Django admin site) to custom one and how to achieve that?
Yes, it's possible.
1) You can move your model to section auth, just add to your class:
class Meta:
app_label = 'auth'
2) You can move Group and User models to your app section, for that variant need to:
Override user model and add it to your app
from django.contrib.auth.models import AbstractUser
class CustomUser(AbstractUser):
pass
also need add to your project settings AUTH_USER_MODEL = 'your_app.CustomUser'
Don't forget declare in admin.py from your app:
class UserAdmin(admin.ModelAdmin):
pass
admin.site.register(CustomUser, UserAdmin)
For group model put this code in admin.py:
from django.db.models.loading import get_models
from django.contrib.auth import models
models = get_models(models)
models[1]._meta.app_label = 'your_app'
3) You can look at django-admin-tools
Here in my model, you can see that I have a SpecializedProfile with a OneToOne relationship with a UserProfile, with a OneToOne relationship with the django user model.
I want to create an admin for the SpecializedProfile containing inlines for the UserProfile and the django User model, so that I can create a SpecializedProfile all at once, without needing to go to the UserProfile page and the User page.
Here is my model:
class UserProfile(models.Model):
user_auth = models.OneToOneField(User, related_name="profile", primary_key=True)
# more fields...
class SpecializedProfile(models.Model):
profile = models.OneToOneField(UserProfile, related_name="specialized_profile", primary_key=True)
# More fields...
and here is my attempt at creating the admin:
class UserInline(admin.TabularInline):
model = User
fk_name = 'profile__specialized_profile'
class ProfileInline(admin.TabularInline):
model = UserProfile
fk_name = 'specialized_profile'
class SpecializedProfileAdmin(admin.ModelAdmin):
model = SpecializedProfile
inlines = [
UserInline, ProfileInline
]
admin.site.register(SpecializedProfile, SpecializedProfileAdmin)
The admin isn't working, and I am getting this error:
<class 'profiles.admin.ProfileInline'>: (admin.E202) 'profiles.UserProfile' has no field named 'trainer'.
<class 'profiles.admin.UserInline'>: (admin.E202) 'auth.User' has no ForeignKey to 'profiles.SpecializedProfile'.
It seems like django wants the inlines to be on the models where the OneToOne fields are defined, and won't accept reverse relationships. I'd rather not have to go restructuring my models to make this work... is there anything I can do to make the inlines work with my model as-is?
I fixed that error by making reverse side inline, not from Profile to User but from overridden User to Profile:
class ProfileInline(admin.StackedInline):
model = Profile
class IspUserAdmin(UserAdmin):
list_display = ('username', 'first_name', 'last_name', 'email', 'is_staff', 'is_superuser', 'is_active')
list_filter = ('date_joined', 'last_login', 'is_staff', 'is_superuser', 'is_active',)
inlines = (ProfileInline,)
admin.site.unregister(User)
admin.site.register(User, IspUserAdmin)
Then I also tweaked Profile admin (removed Add action and changed some field links to custom ones).
There's a django module on github that will do this for you, without you having to reverse the relationships: django_reverse_admin.
Once installed, your admin would look like:
# admin.py
from django_reverse_admin import ReverseModelAdmin
class SpecializedProfileAdmin(ReverseModelAdmin):
model = SpecializedProfile
inline_reverse = ['profile']
inline_type = 'tabular' # could also be 'stacked'
admin.site.register(SpecializedProfile, SpecializedProfileAdmin)
Unfortunately, I don't think it can do nested inlines (Django can't either), so that would only solve part of your problem. I know you didn't want to change your database structure, but SpecializedProfile really seems more like a subclass of UserProfile. If you rewrote your model like so:
class SpecializedProfile(UserProfile):
# More fields...
Then you could have the admin like this:
# admin.py
from django_reverse_admin import ReverseModelAdmin
class UserProfileAdmin(ReverseModelAdmin):
model = UserProfile
inline_reverse = ['user_auth']
inline_type = 'tabular'
class SpecializedProfileAdmin(ReverseModelAdmin):
model = SpecializedProfile
inline_reverse = ['user_auth']
inline_type = 'tabular'
admin.site.register(SpecializedProfile, SpecializedProfileAdmin)
admin.site.register(UserProfile, UserProfileAdmin)
This way, you can view everything inline for both UserProfile and SpecializedProfile.
Good evening,
I am presently creating a site with Django and I extended the user with a user profile. I have a small problem though. Here is my situation:
I extended the user profile in order to add custom fields.
I added the model to the User Admin Model, so when I am adding a user, I can fill in directly the fields to create the profile.
Now, if I don't add ANYTHING in these new custom user fields, in the user add page, Django Admin won't throw me an error saying these fields are null (and they aren't suppose to be)
I want it to throw me an error in this User Add Admin page, so that the admins will HAVE to fill in a profile when adding a new user.
ALL the users will be added in the Admin Panel.
Is this possible? Thanks a lot!
in admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as DjangoUserAdmin
from django.contrib.auth.models import User
from accounts.models import UserProfile
class UserProfileInline(admin.TabularInline):
model = UserProfile
class UserAdmin(DjangoUserAdmin):
inlines = [ UserProfileInline,]
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
In model.py
class UserProfile(models.Model):
user = models.OneToOneField(User)
employee_number = models.PositiveIntegerField(unique=True)
def __unicode__(self):
return 'Number'
By default, empty inline is permitted and thus no further check would be taken for an empty form. You need to override it manually:
class UserProfileForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(UserProfileForm, self).__init__(*args, **kwargs)
if self.instance.pk is None:
self.empty_permitted = False # Here
class Meta:
model = UserProfile
class UserProfileInline(admin.TabularInline):
model = UserProfile
form = UserProfileForm