I am new to Django and I have been trying this for weeks, but could not find a way to solve this problem.
I want to store additional information like user mobile number, bank name, bank account. And want to store the mobile number while user registers and wants user to login with either (mobile number and password) or (email and password).
This is my UserProfile model
from django.db import models
from django.contrib.auth.models import User
from django.contrib.auth.models import AbstractUser
# Create your models here.
class UserProfile(AbstractUser):
user_mobile = models.IntegerField(max_length=10, null=True)
user_bank_name=models.CharField(max_length=100,null=True)
user_bank_account_number=models.CharField(max_length=50, null=True)
user_bank_ifsc_code = models.CharField(max_length=30,null=True)
user_byt_balance = models.IntegerField(max_length=20, null=True)
And this is my forms.py
from django import forms
from django.contrib.auth.models import User # fill in custom user info then save it
from django.contrib.auth.forms import UserCreationForm
from models import UserProfile
from django.contrib.auth import get_user_model
class MyRegistrationForm(UserCreationForm):
email = forms.EmailField(required = True)
mobile = forms.IntegerField(required=True)
class Meta:
model = UserProfile
fields = ('username', 'email', 'password1', 'password2','mobile' )
def save(self,commit = False):
user = super(MyRegistrationForm, self).save(commit = False)
user.email = self.cleaned_data['email']
user.user_mobile = self.cleaned_data['mobile']
user.set_password(self.cleaned_data["password1"])
user_default = User.objects.create_user(self.cleaned_data['username'],
self.cleaned_data['email'],
self.cleaned_data['password1'])
user_default.save()
if commit:
user.save()
return user
In my settings.py I have included
AUTH_USER_MODEL = "registration.UserProfile"
admin.py of my app is
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from models import UserProfile
class UserProfileInline(admin.StackedInline):
model = UserProfile
can_delete = False
verbose_name_plural = 'userprofile'
class UserProfileAdmin(UserAdmin):
inlines = (UserProfileInline, )
admin.site.register(UserProfile, UserProfileAdmin)
While adding the user from admin I get this error
Exception at /admin/registration/userprofile/1/
<class 'registration.models.UserProfile'> has no ForeignKey to <class 'registration.models.UserProfile'>
Can someone help me with this or point out to the full working exapmle, I have seen Django documentation but didn't find any luck. Or if there is another way to do this.
Thanks in advance
Edit 1:
While registering from the registration form I'm also getting this error
DatabaseError at /register
(1146, "Table 'django_auth_db.auth_user' doesn't exist")
You have confused yourself a bit here. The idea of subclassing AbstractUser - and defining AUTH_USER_MODEL as your subclass - is that the new model completely replaces auth.models.User. You shouldn't be importing the original User at all, and you certainly should be calling User.objects.create_user(): your new model's manager now has its own create_user method.
Because of this, there's no reason to muck about with inline admins. Your UserProfile should be registered in the admin using the existing django.contrib.auth.admin.UserAdmin class.
Inlines forms assume that you have a Generic ForeignKey on your model, in this case, the UserProfileAdmin expect a Generic ForeignKey of the UserProfile, that does not exists. Try to do a regular Model Admin, like:
class UserProfileAdmin(admin.ModelAdmin):
can_delete = False
verbose_name_plural = 'userprofile'
admin.site.register(UserProfile, UserProfileAdmin)
Related
I've been learning Django and I'm trying to understand how to extend some of the built-in functionality. To do that I've referenced Customizing Authentication in Django and tried to implement the instructions I've found there in a standard django-admin project.
The problem is that when I try to save the form to the database (sqlite3 included db), nothing is recorded. The form passes the is_valid check, but when I check the database however, nothing has been added to either my user or patients tables.
Hoping someone can point out where this is going wrong, thank you.
models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
isPatient = models.BooleanField(default=False)
class Patient(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
age = models.PositiveIntegerField()
forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.db import transaction
from .models import *
class RegisterPatient(UserCreationForm):
age = forms.IntegerField()
class Meta:
model = User
fields = UserCreationForm.Meta.fields + ("age")
#transaction.atomic
def save(self, commit=True):
user = super(RegisterPatient, self).save(commit=False)
user.isPatient = True
user.save()
patient = Patient.objects.create(user=user)
patient.firstName.add(*self.cleaned_data.get('age'))
patient.save()
views.py
def register(response):
form = RegisterPatient(response.POST)
if form.is_valid():
print("is Valid") # < Code reaches here
form.save
return redirect("/")
settings.py
AUTH_USER_MODEL = 'main.User'
admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from . models import User
admin.site.register(User, UserAdmin)
You need to replace form.save with form.save(). The latter calls the save function, whereas the former does not.
I am having two models projects and User in projects the User is related like shown below
models.py:
class project(models.Model):
user=models.OneToOneField(User,on_delete=models.CASCADE)
room = models.ForeignKey(room,on_delete=models.CASCADE)
goal = models.ManyToManyField(goal)
design = models.ManyToManyField(design)
furniture = models.ForeignKey(furniture,on_delete=models.CASCADE)
created_at = models.DateTimeField(default=datetime.now)
updated_at = models.DateTimeField(default=datetime.now)
Now here I want to display the extra column as projects in user page in django admin for every user when I click on that it should take to particular project detail page of that user
Screenshots:
This is the user list page
This is the project list page
This is the project detail page
admin.py:
from django.contrib import admin
from .models import project
class ProjectAdmin(admin.ModelAdmin):
readonly_fields = ('user','room','goal','design','furniture','created_at','updated_at')
admin.site.register(project,ProjectAdmin)
Please help me out Thanks in advance
You would need to write a custom admin for your User:
from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin
from django.utils.safestring import mark_safe
UserModel = get_user_model()
admin.site.unregister(UserModel)
#admin.register(UserModel)
class CustomUserAdmin(UserAdmin):
list_display = (
'username', 'email', 'first_name', 'last_name', 'user_project'
)
def user_project(self, obj):
url = '/admin/modsy/project/{}/change/'.format(obj.project.pk)
return mark_safe('view project'.format(url))
I was dealing with user authentication in django and created a UserProfile model with foreign key to User in-built model. Then I created explicitly defined User model and then deleted it to restore the original code.
But now in my UserProfile database accessed from admin page is showing (None) for all the profiles created earlier.
And when I click on it it shows an error.
This is the code:
forms.py and models.py
from django import forms
from django.contrib.auth.models import User
from cms.models import UserProfile
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput)
class Meta:
model = User
fields = ('username', 'email', 'password')
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('designation',)
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User)
designation = models.CharField(max_length=128,blank=True)
def __unicode__(self):
return self.user.username
How do I delete that (None)?
As I said in comments, it's because your __unicode__() built-in method prints this user
Try change this part of the code to:
def __unicode__(self):
try:
return self.user.username
except:
return "UserProfile has No User instance"
Every user has (should have) a UserProfile object, and every UserProfile can have Locations against it (foreign key in Location). I want to show these Locations (and allow editing/adding/deleting them) in the User view in the admin site. Nested inlines aren't possible, so I'd like to add a LocationInline to the User page, which I'm unsure how to do.
models.py
from django.db import models
from registration.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User)
# ...
class Location(models.Model):
owner = models.ForeignKey(UserProfile)
# Address and stuff
admin.py
from django.contrib import admin
from django.contrib.auth.models import User
from main.models import UserProfile, Location
from django.contrib.auth.admin import UserAdmin as AuthUserAdmin
class UserProfileInline(admin.StackedInline):
model = UserProfile
max_num = 1
can_delete = False
class LocationInline(admin.TabularInline):
model = Location
extra = 1
class UserAdmin(AuthUserAdmin):
inlines = [UserProfileInline, LocationInline]
# Obviously doesn't work, because Location is from UserProfile, not User
# How can I make it use user.profile instead?
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
My site makes use of Django's User Authentication User model and a custom UserProfile model to store some additional data (birthday, etc.). Is there a way to create a view in Django admin that weaves together fields from both the User and UserProfile models?
I suspect that this code snippet is not even close, but maybe it will help illustrate what I'm trying to do:
from django.contrib import admin
from django.contrib.auth.models import User
from userprofile.models import UserProfile
class UserProfileAdmin(admin.ModelAdmin):
list_display = ('name', 'gender', 'User.email') #user.email creates the error - tried some variations here, but no luck.
admin.site.register(UserProfile, UserProfileAdmin)
Error message:
ImproperlyConfigured: UserProfileAdmin.list_display[2], 'User.email' is not a callable or an attribute of 'UserProfileAdmin' or found in the model 'UserProfile'.
Ultimately, I'm trying to create an admin view that has first & last name from UserProfile and email from User.
for displaying user email you need to have a method on UserProfile or UserProfileAdmin that returns the email
on UserProfile
def user_email(self):
return self.user.email
or on UserProfileAdmin
def user_email(self, instance):
return instance.user.email
then change your list_display to
list_display = ('name', 'gender', 'user_email')
Related docs: ModelAdmin.list_display
You could try using InlineModelAdmin to display both User and UserPofile forms in a admin view.
To display user profile information in change list you can create a new method that delegates the values from UserProfile to User model.
For example this should work more or less :)
from django.contrib import admin
from django.contrib.auth.models import User
from my_models import UserProfile
class UserProfileInline(admin.StackedInline):
model = UserProfile
fk_name = 'user'
class UserAdmin(admin.ModelAdmin):
list_display = ['get_userprofile_name', 'email']
list_select_related = True
inlines = [
UserProfileInline,
]
def get_userprofile_name(self, instance):
# instance is User instance
return instance.get_profile().name
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
Using Ashoks top answer i made snippet that simplifies this process for large number of fields
class ColumnViewer(object):
pass
column_list = ('name', 'surname', )
for col in column_list:
setattr(ColumnViewer, col, lambda s,i : getattr(i, col))
#admin.register(UserProfile)
class UserProfileAdmin(admin.ModelAdmin, ColumnViewer):
list_display = column_list