#python #django #django-forms #django-admin
Вопрос:
TLDR: Как заставить пользовательскую форму вести себя так, как формы, которые Django создает для вас при регистрации модели на сайте администратора, где форма доступна для редактирования, когда у пользователя есть разрешения на изменение, но только для чтения, когда у пользователя есть только разрешения на просмотр
У меня есть проблема. У меня есть пользовательские формы для большинства моих моделей, так как я выполняю большую часть проверки и обработки данных с помощью форм вместо представлений, так что опыт или поведение, когда пользователь выполняет свои действия через мой сайт или панель администратора Django, одинаковы.
Для моделей, зарегистрированных на сайте администратора без пользовательских форм (только для модели регистрации) — они ведут себя безупречно в соответствии с пользовательскими настройками. Если у них есть change_modelname
завивки, они могут щелкнуть ссылку на объекте и перейти в DetailView
форму, в которой они могут вносить изменения. Если у них есть только view_modelname
завивка, их отнесут к DetailView
тому, что сейчас есть у всех readonly
.
Для моделей, зарегистрированных на сайте администратора с помощью моих пользовательских форм, однако — для пользователей, у которых есть только разрешения на просмотр (без прав на изменение), KeyError
при нажатии на объект вместо возможности просмотра DetailView
в readonly
режиме.
Я посмотрел, как это решить, в том числе попытался узнать из исходного кода, как Django делает это с формами, которые они генерируют из наших моделей по умолчанию, но, похоже, не нашел ничего полезного для меня.
То, что я пробовал до сих пор, — это проверка пользовательских настроек в методе admin.ModelAdmin
экземпляра get_form
-если у пользователя есть change_modelname
настройки, я передам им свою пользовательскую форму, иначе ничего не делайте. Поначалу кажется, что это работает , пользователь без change_modelname
завивки, но с view_modelname
завивкой может попасть в DetailView readonly
, так как они встречаются с формой, которую Django создает из модели, а не из моей собственной. Когда я потом дам им change_modelname
завивку, им, как и ожидалось, будет выдана моя пользовательская форма. Но когда я отменю это change_modelname
разрешение (путем изменения настроек группы пользователя или удаления их из группы), они снова встречаются KeyError
, поскольку Django все еще пытается предоставить им мою пользовательскую форму по причинам, о которых я не знаю. Почему они выполняют проверку в первый раз, но не во второй?
Несмотря на это, я все равно думал, что это решение было скорее хитрым обходным путем. В идеале я хотел бы знать, как создать пользовательскую форму, наиболее подходящую для Django, которая позволяет ей вести себя так, как ожидается, в соответствии с perms-создайте форму readonly
, когда у пользователя есть только view_modelname
perms, например, как ведут себя формы, созданные Django. Не стесняйтесь также сообщить мне, что я мог бы сделать лучше с помощью моего дурацкого обходного пути, который я попытался. Спасибо!
Note: I’ve also tried figuring out how to make it so that the Django Admin site does not provide a link to the DetailView
of an object to begin with if they do not have change_modelname
perms.
Code:
admin.py
class IotDeviceAdmin(admin.ModelAdmin):
list_display = ['name', 'desc', 'owner', 'mac_address']
search_fields = ['name', 'desc', 'owner', 'mac_address']
def get_form(self, request, obj=None, **kwargs):
# if updating
if obj:
# if user has change perms
if request.user.has_perm('iot.change_iotdevice'):
# give custom update form
self.form = IotUpdateForm
# if creating
else:
# give custom create form
self.form = IotCreateForm
return super(IotDeviceAdmin, self).get_form(request, obj, **kwargs)
forms.py
class IotUpdateForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(IotUpdateForm, self).__init__(*args, **kwargs)
self.fields['owner'].disabled = True
self.fields['device_name'].disabled = True
try:
updating_device = IotDevice.objects.get(mac_address=self.instance.mac_address)
except ObjectDoesNotExist as e:
# log error
else:
if updating_device.approved:
self.fields['mac_address'].disabled = True
class Meta:
model = IotDevice
fields = ['name', 'desc', 'owner', 'mac_address']
def clean_my_fields(self):
# clean
return my_fields
models.py
class IotDevice(models.Model):
owner = models.CharField(max_length=100)
name = models.CharField("Device Name", unique=True, max_length=100)
desc = models.CharField("Device Description", max_length=200)
mac_address = models.CharField("MAC Address", unique=True, max_length=17)
class Meta:
verbose_name = "IoT Device"
def __str__(self):
return self.name