Say I have a basic CreateView form, like this, to allow new users to register on a site:
from django.contrib.auth import get_user_model
from django.http import HttpResponse
from django.views.generic import CreateView
User = get_user_model()
class Signup(CreateView):
model = User
fields = ['first_name', 'last_name', 'email', 'password']
I just tried this, and found that the password field is rendered in plain text; how would I go about overriding the view so that it uses forms.PasswordInput() instead? (I realise it's probably easiest to just define the form by hand, but I'm just curious about how you'd do that.)
You could override get_form(), and modify the form to change the widget on the password field:
from django import forms
class Signup(CreateView):
model = User
fields = ['first_name', 'last_name', 'email', 'password']
def get_form(self, form_class):
form = super(Signup, self).get_form(form_class)
form.fields['password'].widget = forms.PasswordInput()
return form
But an even better way would be to just create a custom form class. In the custom class just set widgets on the Meta class. Like this:
from django import forms
class SignupForm(forms.ModelForm):
class Meta:
model = User
fields = ['first_name', 'last_name', 'email', 'password']
widgets = {
'password': forms.PasswordInput()
}
class Signup(CreateView):
form_class = SignupForm
model = User
Usually you would put the custom form class in a forms.py file as well.
Not sure if this affected earlier versions of Django, but in more recent versions the get_form() should have a default form_class=None when overriding that method.
The updated (Python 3, Django 2.2) example would be:
from django import forms
class Signup(CreateView):
model = User
fields = ['first_name', 'last_name', 'email', 'password']
def get_form(self, form_class=None):
form = super().get_form(form_class)
form.fields['password'].widget = forms.PasswordInput()
return form
https://docs.djangoproject.com/en/2.2/ref/class-based-views/mixins-editing/#django.views.generic.edit.FormMixin
Related
I need to add this widget to the django UpdateView,
class tlistUpdate(LoginRequiredMixin,UpdateView):
fields = ('title', 'thumbnail', 'content', 'tags')
model = htmlpage
template_name = 'blog/create_form.html'
Tried adding
widgets = {
'content': SummernoteWidget(),
}
and
content = forms.CharField(widget=SummernoteWidget())
But it did't work.
The UpdateView is not constructed to handle advanced form construction. The idea is that you use fields if you aim to construct a simple (standard) Form.
You can simply construct a ModelForm and use that form in your CreateView/UpdateView:
# app/forms.py
from django import forms
class HtmlPageForm(forms.ModelForm):
class Meta:
model = HtmlPage
fields = ('title', 'thumbnail', 'content', 'tags')
widgets = {
'content': SummernoteWidget
}
In your views.py you can then use the form by setting the form_class attribute [Django-doc]:
# app/views.py
from app.forms import HtmlPageForm
class TlistUpdate(LoginRequiredMixin,UpdateView):
model = htmlpage
form_class = HtmlPageForm
template_name = 'blog/create_form.html'
Note: normally a Django models, just like all classes in Python are given a name in PerlCase, not snake_case, so it should be: HtmlPage instead of htmlpage.
Essentially I have a custom UserChangeForm that uses my user model 'Writer' and I want to set the default for all the fields as the current value from the database(or the value from the request user). What would be the best way to go about this?
I tried to set the defaults in the form however the request object isn't accessable in forms.py
the form...
class writerChangeForm(UserChangeForm):
class Meta:
model = Writer
fields = ('username', 'email', 'first_name', 'last_name', 'country')
country = CountryField().formfield()
widgets = {'country': CountrySelectWidget()}
The view...
class ProfileView(generic.CreateView):
form_class = writerChangeForm
template_name = 'diary/profile.html'
Thanks for any input!
The best way will be to override get_initial() method.
class ProfileView(generic.CreateView):
form_class = writerChangeForm
template_name = 'diary/profile.html'
def get_initial(self):
# get_initial should return dict. They should be rendered in template.
writer = Writer.objects.get(pk=1) # first get data from database.
# dictionary key names should be same as they are in forms.
return {
'username': writer.username,
'email': writer.email,
'first_name': writer.first_name
}
Django==2.2.1
GDAL==2.3.2
django-username-email==2.2.4
I have a simple Django application with a custom user model based on django-username-email's AbstractCUser, which removes the username from the user model, using e-mail address instead. On the user model, I defined a PointField field storing the user's current location.
models.py
from django.contrib.gis.db import models as gis_models
from cuser.models import AbstractCUser
class User(AbstractCUser):
"""Custom user model that extends AbstractCUser."""
current_location = gis_models.PointField(null=True, blank=True,)
I would like to register this model in Django admin so that I can register new users and view/set their location with a map widget. This kind of works if I use a custom user admin based on admin.OSMGeoAdmin in combination with a custom user change form:
admin.py
from django.contrib.gis import admin
from django.contrib.auth import get_user_model
from .forms import CustomUserCreationForm, CustomUserChangeForm
class CustomUserAdmin(admin.OSMGeoAdmin):
model = get_user_model()
add_form = CustomUserCreationForm # <- there seems to be a problem here
form = CustomUserChangeForm
list_display = ['email', 'last_name', 'first_name']
readonly_fields = ['last_login', 'date_joined']
admin.site.register(get_user_model(), CustomUserAdmin)
forms.py
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = get_user_model()
exclude = ('username',)
class CustomUserChangeForm(UserChangeForm):
class Meta(UserChangeForm.Meta):
model = get_user_model()
fields = (
'email',
'first_name',
'last_name',
'current_location',
# ...
)
When I open an existing user record in the Django admin, the required fields are displayed as intended, and the current location is displayed on a map. However, the same form seems to be used for user creation as well (i.e. add_form has no effect), which makes it impossible to add new users via the admin, because the password setting functionality is not embedded correctly (see screen shot).
The problem seems to be that OSMGeoAdmininherits from ModelAdmin, which in contrast to the standard UserAdmindoes not have an add_form property.
Is there any way to specify a custom user creation form in this case (ideally the UserCreationForm provided by django-username-email while maintaining the ability to display point fields on a map on the user change form?
You need to override get_form similar to how django.contrib.auth.admin.UserAdmin does.
def get_form(self, request, obj=None, **kwargs):
"""
Use special form during user creation
"""
defaults = {}
if obj is None:
defaults['form'] = self.add_form
defaults.update(kwargs)
return super().get_form(request, obj, **defaults)
Following schillingt's suggestion, this is the code I ended up using:
from django.contrib.gis import admin
from django.contrib.auth import get_user_model
from cuser.forms import UserCreationForm
from .forms import CustomUserChangeForm
class CustomUserAdmin(admin.OSMGeoAdmin):
model = get_user_model()
add_form = UserCreationForm
form = CustomUserChangeForm
list_display = ['email', 'last_name', 'first_name']
readonly_fields = ['last_login', 'date_joined']
def get_form(self, request, obj=None, **kwargs):
"""
Use special form during user creation.
Override get_form method in the same manner as django.contrib.auth.admin.UserAdmin does.
"""
defaults = {}
if obj is None:
defaults['form'] = self.add_form
defaults.update(kwargs)
return super().get_form(request, obj, **defaults)
admin.site.register(get_user_model(), CustomUserAdmin)
I need to make the email field in the Django User model mandatory. It isn't obvious to me how to do that. Suggestions welcome. I am currently using:
from django.contrib.auth.forms import UserCreationForm
for my User creation form, and combining this with my own custom UserProfileCreateForm
Ian
You should be able subclass the provided registration form and override properties of a field in the Meta class.
from django.contrib.auth.forms import UserCreationForm
# Not sure about the syntax on this one. Can't find the documentation.
class MyUserCreationForm(UserCreationForm):
class Meta:
email = {
'required': True
}
# This will definitely work
class MyUserCreationForm(UserCreationForm):
def __init__(self, *args, **kwargs):
super(MyUserCreationForm, self).__init__(*args, **kwargs)
self.fields['email'].required = True
from django import forms
from django.contrib.auth.models import User
class MyUserForm(forms.ModelForm):
email = forms.CharField(max_length=75, required=True)
class Meta:
model = User
fields = ('username', 'email', 'password')
use EmailField in your model
see more at
https://docs.djangoproject.com/en/2.1/ref/models/fields/#emailfield
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