I was trying to extend user profile. I founded a few solutions, but the most recommended was to create new user class containing foreign key to original django.contrib.auth.models.User class. I did it with this so i have in models.py:
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
website_url = models.URLField(verify_exists=False)
and in my admin.py
from django.contrib import admin
from someapp.models import *
from django.contrib.auth.admin import UserAdmin
# Define an inline admin descriptor for UserProfile model
class UserProfileInline(admin.TabularInline):
model = UserProfile
fk_name = 'user'
max_num = 1
# Define a new UserAdmin class
class MyUserAdmin(UserAdmin):
inlines = [UserProfileInline, ]
# Re-register UserAdmin
admin.site.unregister(User)
admin.site.register(User, MyUserAdmin)
And now when I'm trying to create/edit user in admin panel i have an error:
"Unknown column 'content_userprofile.id' in 'field list'" where content is my appname.
I was trying to add line AUTH_PROFILE_MODULE = 'content.UserProfile' to my settings.py but with no effect.
How to tell panel admin to know how to correctly display fields in user form?
After some effort I found working solution:
the AUTH_PROFILE_MODULE = 'content.UserProfile' is required
please drop your database (auth_user, yourapp_userprofile tables should be enough)
finally python manage.py syncdb
Related
Hi I am new to Django and I have created a login/logout model Django inbuilt User and UserCreationForm. It is working fine but my issue is I have define two custom inputs in my form and it is displaying on the web page when I run the server but when I check the user under the admin, I only see the details of User defined fields not my custom fields.
How to save it's data to my User model?
or maybe If I defined the custom fields wrong how do I change it so that I can save it's data in my model.
My custom defined fields that is address and phone number is not showing in Admin User and it's data is not getting saved.
model.py
from django.db import models
from django.contrib import auth
# Create your models here.
class User(auth.models.User,auth.models.PermissionsMixin):
def __str__(self):
return "#{}".format(self.username)
forms.py
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import UserCreationForm
from django import forms
class UserCreateform(UserCreationForm):
address = forms.CharField(max_length=150, required=True)
phone_number = forms.IntegerField(required=True)
class Meta(UserCreationForm.Meta):
model = get_user_model()
fields = ('username','email','password1','password2')
def __init__(self,*args,**kwargs):
super().__init__(*args,**kwargs)
self.fields['username'].label = 'Display Name'
views.py
from django.shortcuts import render
from django.urls import reverse_lazy
from django.views.generic import CreateView
from . import forms
# Create your views here.
class SignUp(CreateView):
form_class = forms.UserCreateform
success_url = reverse_lazy('login')
template_name = 'account/signup.html'
Adding fields to a ModelForm doesn't do anything in terms of saving them, if they are not fields of the Model. So of course, address and phone_number aren't saved, your User model doesn't have those fields.
You need to have a Model to save those fields. As explained here, you have two options:
Create a Profile model to save all extra fields
Create a custom User model, subclassing AbstractUser or AbstractBaseUser.
My advice: Do both. Save your extra fields in a Profile model.
And subclass AbstractUser, so you have the option to add useful methods and properties to the User model (right now, just __str__()).
Why not just subclass? Because as your app grows, you'll want to add more an more things to a user's profile. Maybe you want to create different types of profiles, e.g. the private profile and the professional profile. The User itself should be compact, just managing authentication and permissions.
Note: your current User model is wrong. You must not subclass auth.User but auth.AbstractUser.
This is how looks template of Django Admin Model:
This is model which I created:
class ProfileUser(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
profile_image = models.URLField()
is_qualified = models.BooleanField(default=False)
How can I create same filter menu ? for is_qualified ?
You can specify this in the list_filter attribute [Django-doc] of the ModelAdmin you make for your model:
from django.contrib import admin
from app.models import ProfileUser
class ProfileUserAdmin(admin.ModelAdmin):
list_filter = ('is_qualified',)
admin.site.register(ProfileUser, ProfileUserAdmin)
It is however advisable only to use this for fields with a limited number of options (a BooleanField of course is a good candidate for this).
I have a Django's default UserCreationForm to add a new user via Admin app. I want to add new fields from another custom model called UserProfile. The UserProfile has a One-to-One relationship with Django's User model. The additional fields which UserProfile model has are phone number, company name etc.
Is there a way where I can merge UserProfile form with Django's default User form while creation of the new user from Admin panel?
I looked at Django's documentation here on Inline forms but seems their require foreign key relationship.
Django 2.1
Assuming you have Profile with extra field phone_number. Like this
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
phone_number = models.CharField(max_length=24)
You can follow following steps to add extra fields in UserCreationForm in Admin.
1. Create custom UserCreationForm
Inherit from UserCreationForm and Add extra fields and functionality.
from django import forms
from django.contrib.auth.forms import UserCreationForm
from account.models import Profile
class UserWithProfileCreationForm(UserCreationForm):
phone_number = forms.CharField(max_length=32)
def save(self, commit=True):
instance = super().save(commit=True)
profile = Profile(user=instance, phone_number=self.cleaned_data['phone_number'])
profile.save()
return instance
2. Unregister (already registered) User model and register again with custom form and fields
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
# unregister first
admin.site.unregister(User)
#admin.register(User)
class UserWithProfileAdmin(UserAdmin):
add_form = UserWithProfileCreationForm
add_fieldsets = (
(None, {
'classes': ('wide',),
# add any custom fields here
'fields': ('username', 'password1', 'password2', 'phone_number'),
}),
)
There are two ways to do this.
First, you can create a custom User model from AbstractBase
# models.py
class MyUser(AbstractBaseUser):
profile = models.OneToOneField(UserProfile)
And then update your admin view.
#admin.py
from django.contrib.auth.admin import UserAdmin
class UserProfileInline(admin.TabularInline):
model = UserProfile
class MyUserAdmin(UserAdmin):
inlines = [
UserProfileInline,
]
admin.site.register(MyUser, MyUserAdmin)
Second, you can simply add the OneToOneField(User) in your UserProfile model, and follow the similar method to update the admin view.
I created a profile model that contains additional fields for the User model. It works as expected, but when I add a new user, the added fields appear on both the "Add user" page (first page) and the "Change user" page (second page). How can I prevent my added fields from appearing on the "Add user" page?
models.py
from django.db import models
from django.contrib.auth.models import User
class Member(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
my_added_field = models.CharField(max_length=15)
admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from .models import Member
class MemberInline(admin.StackedInline):
model = Member
class MemberAdmin(UserAdmin):
inlines = (MemberInline,)
admin.site.unregister(User)
admin.site.register(User, MemberAdmin)
You need to use exclude = 'your-field-name' in Meta 'your-field-name' is field which you not want to show in admin section.
I'm trying to get the Django Admin interface to display information about my profile. It displays all of my users but no profile information. I'm not quite sure how to get it to work.
I found this code after a quick google search:
from auth.models import UserProfile
from django.contrib import admin
from django.contrib.auth.models import User
from django.contrib.auth.admin import UserAdmin
admin.site.unregister(User)
class UserProfileInline(admin.StackedInline):
model = UserProfile
class UserProfileAdmin(UserAdmin):
inlines = [UserProfileInline]
admin.site.register(User, UserProfileAdmin)
However, I don't think that it worked. When I log into the admin page, I see Users, Groups, and Sites. I click Users and I see a list of all of my Users, but no indication of any profile. Clicking on a user shows me info about that user, but still no profile information.
If it will help, here is my model declaration:
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
company = models.CharField(max_length=30)
user = models.ForeignKey(User, unique=True)
And my registration code:
def register(request):
if request.method == 'POST':
uf = UserForm(request.POST)
upf = UserProfileForm(request.POST)
if uf.is_valid() and upf.is_valid():
user = uf.save()
userprofile = upf.save(commit=False)#need to get the user profile object first
userprofile.user = user #then set the user to user
userprofile.save() #then save to the database
return HttpResponseRedirect('/auth/login/')
else:
uf = UserForm()
upf = UserProfileForm()
return render_to_response('register.html', dict(userform=uf,userprofileform=upf),context_instance=RequestContext(request))
I can't see exactly what's wrong, but here's a slightly simpler example that I know works. Put this is any working admin.py. Try adding a trailing comma to your inline-- some things break without it.
from django.contrib import admin
from django.contrib.auth.models import User
from django.contrib.auth.admin import UserAdmin
from accounts.models import UserProfile
admin.site.unregister(User)
class UserProfileInline(admin.StackedInline):
model = UserProfile
class UserProfileAdmin(UserAdmin):
inlines = [ UserProfileInline, ]
admin.site.register(User, UserProfileAdmin)
This is not exactly an answer to your question BUT, according to Django Admin documentation, you can display information from UserProfile in your User "table". And you can make it searchable.
That would look something like this (modifying answer from C. Alan Zoppa):
class UserProfileAdmin(UserAdmin):
inlines = [ UserProfileInline, ]
def company(self, obj):
try:
return obj.get_profile().company
except UserProfile.DoesNotExist:
return ''
list_display = UserAdmin.list_display + ('company',)
search_fields = UserAdmin.search_fields + ('userprofile__company',)
You might have an issue though with search if your profile class is no longer called UserProfile.
The missing comma shouldn't matter. I suspect the problem is that you added a new admin.py but the development server didn't recognize it. If you restart the development server, it'll see the new file.