Disable Fields from Editing in Django - django

I have a form with several fields that I would like to show to the user but prevent them from editing (should not be an edit box).
My form class looks like this and I'm using the fields meta to have them automatically defined. I'm looking to prevent user from changing their username and email after registration.
class UserEditForm(forms.ModelForm):
class Meta:
model = User
fields = ('username', 'first_name', 'last_name', 'email', 'password')
The question In a Django form, how do I make a field readonly (or disabled) so that it cannot be edited?
doesn't provide an answer to what to do if the fields are defined automatically using meta.
I've tried
disabled = ('username', 'email',)
And a few other options but nothing seems to work.
I'm looking to prevent someone from also changing the form and submitting it (and the data getting changed) as the previous question suggested can be done.
[Edit]: Using Django 1.11

You can set the disabled property on the fields you need to after the form as been initialised:
class UserEditForm(forms.ModelForm):
class Meta:
model = User
fields = ('username', 'first_name', 'last_name', 'email', 'password')
def __init__(self, *args, **kwargs):
super(UserEditForm, self).__init__(*args, **kwargs)
self.fields['username'].disabled = True
self.fields['email'].disabled = True

Since disabled form elements are ignored in Django form validation, disabling mandatory fields will result in a validation error. Therefore a JQuery fix can do this:
$(document).ready(function() {
... CHECK IF FORM IS IN EDIT STATE ...
// disable form controls
$('select#id_caseType').prop("disabled", true );
Then at Submit method, right before submitting the form, just enable those fields only (so the values will be included in form):
$('#demo-form2').on('submit',function(){
// enable the previously disabled form fields in edit mode
$('select#id_caseType').prop("disabled", false );
Of course this can be done in a generic way by, adding all disabled fields into an array or assigning class that makes JQuery selection easier (ie. all such fields can be added a 'disabled' class)

Although Gavin already answered I'm leaving this if somebody else has the same problem.
I think this is exactly what you were asking:
In admin.py, next to list_display, add this line:
readonly_fields = ('username', 'email',)

Related

how can i check duplicate data in my django database comparing with form data in generic view(Updateview)

I made a Updateview method in Django to update firstname, lastname, mobile etc..but how can I check the data received by the generic view through the form is previously exist in DB. For example, I want to avoid duplicating of mobile number with the model User in the database I tried by approaching def post() method, but I got a lot of errors can you teach me the exact way for avoiding duplicate data inserting
View code
class UpdateMprofile(mixin1, mixin2, UpdateView):
login_url = reverse_lazy('loginurlhere')
model = User
fields = ['first_name', 'last_name', 'mobile', 'avatar']
success_url = reverse_lazy('redirectedviewurlhere')
You should use unique=True in the model field definition, then Django will check this automatically when validating the form.

django inline admin: dynamically delete non-model fields from model form

When I display a user profile inline in the admin, I want to delete some non-model fields based on certain conditions.
class ProfileInline(admin.StackedInline):
model = Profile
form = ProfileForm
max_num = 1
can_delete = False
The ProfileForm has some additional fields, which are not related to the model and I want to delete them under certain conditions, e.g. a certain user is editing the form.
I tried to explicitly set the fields to include and I also tried to exclude the fields with the help of get_formset():
def get_formset(self, request, obj=None, **kwargs):
kwargs['fields'] = ['fieldX', 'fieldY']
#kwargs['exclude'] = ['fieldZ']
return super(ProfileInline, self).get_formset(request, obj, **kwargs)
It works fine with model fields, but the non-model fields are always shown.
This is an old topic, but I think I can help.
You can hide the fields using the fieldsets property of the ModelAdmin class.
Just lists the fields that you want to show.

Django - Display User Email in User Profile Admin

This may be a very simple question, but I haven't been able to find it in SO.
I created a User Profile Model for additional user info via OnetoOneField. Now for the Admin of the User Profile Model, I want to display the email field found in the User model. I tried:
# models.py
def email(self):
return self.user.email
# admin.py
fieldsets = [
('', {'fields': [
...
'email',
...
]})
]
list_display = (
...
'email',
...
)
This worked for the list_display section, but for fieldsets, the following error popped up:
Unknown field(s) (email) specified for UserProfile. Check fields/fieldsets/exclude attributes of class UserProfileAdmin.
Is there a way to work around this? Thank you in advance!
From the documentation:
fields can contain values defined in readonly_fields to be displayed
as read-only.
If you add the name of a callable to fields, the same rule applies as
with the fields option: the callable must be listed in
readonly_fields.
So you need to add:
readonly_fields = ('email',)
to your model admin class, and then it will be available in the fieldset.
Put this
def email(self, obj):
return obj.user.email
in your admin class of userprofile and you will be able to use it in fieldsets.

Django: Attributes not being applied to some fields in custom form

I have a custom form to register a user in my Django application. This custom form is inherited from the django.contrib.auth.forms.UserCreationForm class. In my custom form class, I want to add custom HTML attributes to the fields. When I do this, attributes are added to only some fields and not others. In my case, the custom attribute 'class' is added only to the 'email' field and not 'username' field. Please let me know if I'm doing something wrong here and help me solve the problem.
The code for my custom form is here:
class EmployeeRegistrationForm(UserCreationForm):
class Meta:
model = User
fields = ('username', 'email', 'password1', 'password2')
widgets = {'username':forms.TextInput(attrs={'class':'form-control','placeholder':'username'}),
'email':forms.TextInput(attrs={'class':'form-control','placeholder':'email'})}

Django auth - Adding user fields - displaying in admin

I'm a complete n00b to django & python. I come from a PHP background so you'll have to accept my apologies for that :p.
I'm trying to use the admin panel functionality in django to show different options to different people.
The system should allow admins to add "projects" to a list. "Developers" should then be able to view only projects assigned to them, and only change certain fields.
So I guess the question is two fold:
1) Is allowing the "Developers" to login to the admin system the best method of doing it?
1.a) If so, How do I get a boolean field to display on the admin's user form? I just want to flag is_developer. I've added it as a userProfile but don't understand how to make it display on the form
2) Should I disallow them to login (to the admin panel) and make "frontend" whereby they can only see what they're allowed?
I hope that made sense. I'm a bit all over the place at the moment as it's a complete departure to what i'm used to!
Thanks in advance for any help you can offer me :)
There's a lot going on here, so I'm going to piecemeal my answer.
Is allowing the "Developers" to login to the admin system the best method of doing it?
That depends on your setup. Generally, the admin should only be available to "staff": people that are employed by or directly related to your organization. In fact, in order to login to the admin, a user must have is_staff=True. If all of the users belong to your organization (and can be considered "trusted" as a result), then yes, it's fine to allow them to all access the admin. Otherwise, it's not a good idea, as you're opening yourself up to security risks.
If so, How do I get a boolean field to display on the admin's user form?
In the most simplistic sense, you can add a field to a form by literally adding it to the form class, even if it's a ModelForm which pre-populates its fields from the fields on the model.
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
is_developer = forms.BooleanField(default=False)
I've added it as a userProfile but don't understand how to make it display on the form
UserProfile is a different model, obviously, so its fields are not made available on a form for a User. However, Django does provide the ability to add/edit related models inline with edit form for another model. This is done through inline formsets. In the admin, these are just called "inlines".
class UserProfileInlineAdmin(admin.StackedInline):
model = UserProfile
max_num = 1
can_delete = False
class UserAdmin(admin.ModelAdmin):
inlines = [UserProfileInlineAdmin]
The view you get from an inline admin is clearly distinct from the main form (in this case, that of User), though. You can try it out to see what I mean. It's not horrible, but it's still a noticeable break in the form. The reason I mentioned how to add a field to a form earlier, is that if you wanted, you can make it look all like one form with a little bit of clever misdirection.
class UserAdminForm(forms.ModelForm):
class Meta:
model = User
is_developer = forms.BooleanField(default=False)
def save(self, commit=True):
user = super(UserAdminForm, self).save(commit=commit)
if user.pk:
profile = user.get_profile()
profile.is_developer = self.cleaned_data.get('is_developer')
profile.save()
That's a simplistic example, but the idea is that you add the field(s) manually to the form, and then use them to actually update the other object manually when the main object being edited is saved.
Special notes related to User
Now, since you're dealing with User here, there's a lot more sticky details. First, User already has a UserAdmin and its own forms -- yes plural, forms. If you want to add new functionality, you need to make sure you keep the existing Django functionality in the process.
from django.contrib.auth.admin import UserAdmin
form django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
class CustomUserCreationForm(UserCreationForm):
# do stuff
class CustomUserChangeForm(UserChangeForm):
# do stuff
class CustomUserAdmin(UserAdmin):
form = CustomUserChangeForm
add_form = CustomUserCreationForm
admin.site.unregister(User)
admin.site.register(User, CustomUserAdmin)
Also, UserAdmin has its own set of fieldsets defined. The defaults are:
fieldsets = (
(None, {'fields': ('username', 'password')}),
(_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
(_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser', 'user_permissions')}),
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
(_('Groups'), {'fields': ('groups',)}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('username', 'password1', 'password2')}
),
)
If you want to add a field or fields, you'll need to redefine those two attributes with your fields added where you want them.