Reputation: 4395
Using a custom ModelForm in my default (django admin) change view gives me an empty variable self.fields
if the form gets rendered for a user with only view permissions (new in Django 2.1).
This is my code:
# models.py
class Door(ValidateOnSaveMixin, models.Model):
...
motor_type = models.ForeignKey(
MotorType,
on_delete=models.SET_NULL,
default=None,
blank=True,
null=True)
...
door_type = models.CharField(
max_length=3,
choices=DOOR_TYPES,
null=True,
default=None)
...
vehicle_variant = models.ForeignKey(
VehicleVariant,
on_delete=models.CASCADE)
class Meta:
unique_together = ("vehicle_variant", "location", "motor_type")
...
# admin.py
@admin.register(Door)
class DoorAdmin(ImportExportModelAdmin):
form = DoorAdminForm
list_display = ('descriptor', 'get_customer_link', 'get_variant', 'location', 'get_motor_type_link',
'window_type', 'door_type', 'drum_diameter', 'dist_per_motor_rotation')
fields = ('vehicle_variant', 'description', 'location', 'motor_type',
'drum_diameter', 'window_type', 'door_type')
...
# forms.py
class DoorAdminForm(ModelForm):
class Meta:
model = Door
fields = '__all__'
widgets = {
'motor_type': DoorMotorTypeWidget,
}
def __init__(self, *args, **kwargs):
super(DoorAdminForm, self).__init__(*args, **kwargs)
# this line is crashing on access with a user who has only the view permission, as self.fields is empty
self.fields['vehicle_variant'].queryset = VehicleVariant.objects.all().prefetch_related('customer').order_by('customer__name', 'name')
The root cause is related to the exclude attribute of the Meta class in DoorAdminForm
.
No matter what i write to the fields/exclude attributes, always all of the model's fields get automatically put to the exclude list and prevent self.fields
to be populated. And this makes my code crash.
Of course i can check for 'verhicle_variant' in self.fields
but i don't understand the reason for that behaviour. I also couldn't find the part in the django source which populates the exclude attribute with all model fields.
Anybody has an idea if this is intended? Whats the root cause for that behaviour (ignoring the fields and exclude attribute of the Meta class)?
Upvotes: 3
Views: 1570
Reputation: 2921
The point where all fields get put into exclude
is here:
https://github.com/django/django/blob/cf79f92abee2ff5fd4fdcc1a124129a9773805b8/django/contrib/admin/options.py#L674
I have never used django admin with just 'view' permissions. Haven't really found a lot of information about how this should look like either: django-admin
comes with add- and change-views amongst others, but no viewonly-view
? Almost looks like it doesn't really know what to do with users that do not have 'change' permission. It directs them to the change_view and then notices that they are not allowed to change anything so it displays an empty form?
I suppose you could just declare all the fields as readonly for a viewonly-view?
UPDATE:
The field vehicle_variant
won't be in form.fields
as it would still be excluded due to not having change permission, but at least you don't crash on the form's init. I still have no idea what a change_view without change permissions should look like other than everything being readonly.
class DoorAdminForm(ModelForm):
qs = VehicleVariant.objects.prefetch_related('customer').order_by('customer__name', 'name')
model_field = Door._meta.get_field('vehicle_variant')
vehicle_variant = model_field.formfield(queryset=qs)
class Meta:
model = Door
fields = '__all__'
widgets = {
'motor_type': DoorMotorTypeWidget,
}
Upvotes: 2