Администратор django делает поле доступным только для чтения при изменении obj, но требуется при добавлении нового obj - PullRequest
74 голосов
/ 03 декабря 2010

В админ я хотел бы отключить поле при изменении объекта, но сделать его обязательным при добавлении нового объекта.

Какой путь у Джанго?

Ответы [ 6 ]

146 голосов
/ 03 декабря 2010

Вы можете переопределить метод администратора get_readonly_fields:

class MyModelAdmin(admin.ModelAdmin):

    def get_readonly_fields(self, request, obj=None):
        if obj: # editing an existing object
            return self.readonly_fields + ('field1', 'field2')
        return self.readonly_fields
10 голосов
/ 28 апреля 2017

Если вы хотите установить все поля как только для чтения только в представлении изменений, переопределите административные get_readonly_fields:

def get_readonly_fields(self, request, obj=None):
    if obj: # editing an existing object
        # All model fields as read_only
        return self.readonly_fields + tuple([item.name for item in obj._meta.fields])
    return self.readonly_fields

и , если вы хотите скрыть кнопки сохранения при просмотре изменений :

  1. Изменить вид

    def change_view(self, request, object_id, form_url='', extra_context=None):
        ''' customize edit form '''
        extra_context = extra_context or {}
        extra_context['show_save_and_continue'] = False
        extra_context['show_save'] = False
        extra_context['show_save_and_add_another'] = False # this not works if has_add_permision is True
        return super(TransferAdmin, self).change_view(request, object_id, extra_context=extra_context)
    
  2. Изменить права доступа, если пользователь пытается изменить:

    def has_add_permission(self, request, obj=None):
       # Not too much elegant but works to hide show_save_and_add_another button
        if '/change/' in str(request):
            return False
        return True
    

    Это решение было проверено на Django 1.11

3 голосов
/ 15 апреля 2011

К вашему сведению: в случае, если кто-то столкнется с теми же двумя проблемами, с которыми я столкнулся:

  1. Вы все равно должны объявить любые постоянные readonly_fields в теле класса, так как атрибут класса readonly_fields будетбыть доступным из проверки (см. django.contrib.admin.validation: validate_base (), line.213 appx)

  2. Это не будет работать с Inlines, поскольку объект obj передан get_readonly_fields ()является родительским объектом (у меня есть два довольно хакерских решения с низким уровнем безопасности, использующих css или js)

2 голосов
/ 21 октября 2017

Вариант, основанный на предыдущем превосходном предложении Бернхарда Валланта, который также сохраняет любые возможные настройки, предоставляемые базовым классом (если есть):

class MyModelAdmin(BaseModelAdmin):

    def get_readonly_fields(self, request, obj=None):
        readonly_fields = super(MyModelAdmin, self).get_readonly_fields(request, obj)
        if obj: # editing an existing object
            return readonly_fields + ['field1', ..]
        return readonly_fields
0 голосов
/ 03 декабря 2010

Получил похожую проблему. Я решил это с помощью «add_fieldsets» и «limited_fieldsets» в ModelAdmin.

from django.contrib import admin  
class MyAdmin(admin.ModelAdmin):
 declared_fieldsets = None
 restricted_fieldsets = (
    (None, {'fields': ('mod_obj1', 'mod_obj2')}),
    ( 'Text', {'fields': ('mod_obj3', 'mod_obj4',)}),
 )

 add_fieldsets = (
            (None, {
             'classes': ('wide',),
             'fields': ('add_obj1', 'add_obj2', )}),
             )

См. Например: http://code.djangoproject.com/svn/django/trunk/django/contrib/auth/admin.py

Но это не защищает вашу модель от последующих изменений "add_objX". Если вы тоже этого хотите, я думаю, вам нужно пройти через функцию «Сохранить» класса Model и проверить там изменения.

См .: www.djangoproject.com/documentation/models/save_delete_hooks/

Greez, Ник

0 голосов
/ 03 декабря 2010

Вы можете сделать это, переопределив метод formfield_for_foreignkey в ModelAdmin:

from django import forms
from django.contrib import admin

from yourproject.yourapp.models import YourModel

class YourModelAdmin(admin.ModelAdmin):

    class Meta:
        model = YourModel

    def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
        # Name of your field here
        if db_field.name == 'add_only':
            if request:
                add_opts = (self._meta.app_label, self._meta.module_name)
                add = u'/admin/%s/%s/add/' % add_opts
                if request.META['PATH_INFO'] == add:
                    field = db_field.formfield(**kwargs)
                else:
                    kwargs['widget'] = forms.HiddenInput()
                    field = db_field.formfield(**kwargs)
            return field
        return admin.ModelAdmin(self, db_field, request, **kwargs)
...