I extended the Django User Model and added a required ForeignKeyField called company. Now I also need to Change the default user creation Form. What I tried so far was:
Creating a new Form that Inherits from the default UserCreationForm form:
class MyUserCreationForm(UserCreationForm):
company = forms.ModelChoiceField(queryset=Company.objects.all())
class Meta:
model = MyUser
fields = ('username', 'company')
Adding it to my extended Django Admin:
class ExtendedUserAdmin(UserAdmin):
add_form = MyUserCreationForm
...
admin.site.register(MyUser, ExtendedUserAdmin)
This does not work. What am I missing?
Turns out you don't need to change add_form. All you need to do is add the following to ExtendedUserAdmin:
def __init__(self, model, admin_site):
super().__init__(model, admin_site)
self.add_fieldsets[0][1]['fields'] = ('username', 'password1', 'password2', 'company')
Related
I am having problem with Django.
I am using UserCreationForm and generic CreateView in order for people to sign up and create an account. The code is as follows:
Custom form:
class SignUpCustomUserForm(UserCreationForm):
first_name = forms.CharField(max_length=200)
last_name = forms.CharField(max_length=200)
email = forms.EmailField(max_length=200)
class Meta:
model = User
fields = ['first_name', 'last_name', 'username', 'email', 'password1', 'password2']
View:
class SignUpView(generic.CreateView):
form_class = SignUpCustomUserForm
success_url = reverse_lazy('login')
template_name = 'registration/signup.html'
I do not have a model since I am using CreateView which basically handles the model.
I want to automatically set every new created account as staff, but I can not figure out how to do it. Basically, I am working on a form which users can use to create an account with is_staff privileges and they can use those accounts to login to /admin (the default django admin).
I tried setting model.is_staff to true in the Meta class inside the form class, but it didn't work out.
Any advice or ideas is welcomed.
Thank you
You can set is_staff to True in the .form_valid(…) method:
class SignUpView(generic.CreateView):
form_class = SignUpCustomUserForm
success_url = reverse_lazy('login')
template_name = 'registration/signup.html'
def form_valid(self, form):
form.instance.is_staff = True
return super().form_valid(form)
I'm currently writing a system in Django where I'd like to save a user at the same time i'm creating another model.
Model Code:
class MyModel(models.Model):
user = models.OneToOneField(User,related_name="profile",primary_key=True)
custom_field = models.CharField(...)
The model is more elaborate of course, but it shows the setup of the whole thing.
Example form:
First name: [input]
Last name: [input]
Email: [input]
Password: [pass_input]
Custom Text: [text_input]
Is this at all possible using a ModelForm?
Yes; you could create a ModelForm that corresponds to MyModel:
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ['custom_field']
Then in your view, you could interrupt the save of this form using commit=False (https://docs.djangoproject.com/en/1.11/topics/forms/modelforms/#the-save-method) and set the user value of your new object manually. For example, you could set user = request.user like so:
if form.is_valid():
instance = form.save(commit = False)
instance.user = request.user
instance.save()
form.save_m2m() #if your form has any m2m data to save
Yes. In your forms.py file, add this code:
class UserForm(ModelForm):
class Meta:
model = User
fields = ('first_name', 'last_name', 'email')
class ProfileForm(ModelForm):
class Meta:
model = MyModel
fields = ('customfield1', 'customfield2')
EDIT
Here is a great tutorial on to do this: https://simpleisbetterthancomplex.com/tutorial/2016/07/22/how-to-extend-django-user-model.html
I have a Django app that uses Django REST Framework and Django-allauth. Now, I'm trying to retrieve the avatar URL that's present in the social account. However, I'm having trouble forming the serializer.
For background info, the allauth's SocialAccount is related to the user model via a foreign key:
class SocialAccount(models.Model):
user = models.ForeignKey(allauth.app_settings.USER_MODEL)
# the method I'm interested of
def get_avatar_url(self):
...
Now, here's the serializer I currently have:
class ProfileInfoSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'first_name', 'last_name')
In the end, I'd like to have an extra field avatar_url which takes the result of the method call in the SocialAccount model. How do I do that?
I found a solution using a SerializerMethodField:
class ProfileInfoSerializer(serializers.ModelSerializer):
avatar_url = serializers.SerializerMethodField()
def get_avatar_url(obj, self):
return obj.socialaccount_set.first().get_avatar_id()
class Meta:
model = User
fields = ('id', 'first_name', 'last_name', 'avatar_url')
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.
Using Django 1.1:
The Django admin docs describe using arbitrary methods or attributes on a ModelAdmin object in the list_display class attribute. This is a great mechanism for displaying arbitrary information in the list display for a Model. However, there does not appear to be a similar mechanism for the change form page itself. What is the simplest way to accomplish this useful little feature to display arbitrary, non-field-derived information on the ModelAdmin change form page?
A concrete example of the desired setup:
class CustomUserAdmin(UserAdmin):
def registration_key(self, obj):
"""Special method for looking up and returning the user's registration key
"""
return 'the_key'
list_display = ('email', 'first_name', 'last_name', 'is_active', 'is_staff',
'registration_key') # <- this works
fields = ('email', 'first_name', 'last_name', 'is_active', 'is_staff',
'registration_key') # <- this DOESN'T work?
Add the method to the 'readonly_fields' tuple as well.
Try the following:
class CustomUserAdminForm(forms.ModelForm):
registration_key = forms.IntegerField()
class Meta:
model = User
class CustomUserAdmin(UserAdmin):
def registration_key(self, obj):
"""Special method for looking up and returning the user's registration key
"""
return 'the_key'
list_display = ('email', 'first_name', 'last_name', 'is_active', 'is_staff',
'registration_key') # <- this works
fields = ('email', 'first_name', 'last_name', 'is_active', 'is_staff',
'registration_key')
I've done this before by overriding the template for the change form, and accessing custom methods on the model. Using fields is asking the admin to try to add a form field for your method.