django admin ทำให้ฟิลด์เป็นแบบอ่านอย่างเดียวเมื่อแก้ไข obj แต่จำเป็นเมื่อเพิ่ม obj ใหม่


92

ในผู้ดูแลระบบฉันต้องการปิดการใช้งานฟิลด์เมื่อแก้ไขอ็อบเจ็กต์ แต่ทำให้จำเป็นเมื่อเพิ่มอ็อบเจกต์ใหม่

django จะไปเกี่ยวกับเรื่องนี้อย่างไร?

คำตอบ:


182

คุณสามารถแทนที่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

21
ข้อแม้เล็กน้อย / ข้อแม้สำคัญ: ใช้ไม่ได้กับอินไลน์ ปุ่ม "เพิ่ม X อื่น" แบบไดนามิกจะแสดงฟิลด์แบบอ่านอย่างเดียวเป็น "(ไม่มี)" ไม่ใช่ฟิลด์แบบฟอร์มตามที่คุณต้องการ
Cerin

17

หากคุณต้องการตั้งค่าฟิลด์ทั้งหมดเป็นแบบอ่านอย่างเดียวในมุมมองการเปลี่ยนแปลงให้แทนที่ 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


สมบูรณ์แบบ. นี่คือสิ่งที่ฉันต้องการ!
wogsland

3

FYI: ในกรณีที่มีคนอื่นประสบปัญหาสองประการเดียวกันกับที่ฉันพบ:

  1. คุณยังควรประกาศ readonly_fields อย่างถาวรในเนื้อหาของคลาสเนื่องจากแอตทริบิวต์คลาส readonly_fields จะเข้าถึงได้จากการตรวจสอบความถูกต้อง (ดู django.contrib.admin.validation: validate_base (), line.213 appx)

  2. สิ่งนี้จะใช้ไม่ได้กับ Inlines เนื่องจาก obj ส่งไปยัง get_readonly_fields () คือ obj หลัก (ฉันมีโซลูชันที่ค่อนข้างแฮ็กและมีความปลอดภัยต่ำโดยใช้ css หรือ js)


2
2. จุด - นั่นเป็นเพราะข้อบกพร่องในผู้ดูแลระบบ: # 15602ดูเหมือนว่าจะไม่ได้รับการแก้ไขในเร็ว ๆ นี้ (กิจกรรมล่าสุดเมื่อ 2 ปีที่แล้ว) ดูเหมือนว่าเราจะเหลือโซลูชัน CSS / JS
frnhr

3

รูปแบบตามข้อเสนอแนะที่ยอดเยี่ยมก่อนหน้านี้ของ Bernhard Vallant ซึ่งยังคงรักษาการปรับแต่งที่เป็นไปได้ของคลาสพื้นฐาน (ถ้ามี)

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

2

สถานการณ์ที่มีรูปแบบอินไลน์ยังไม่ได้รับการแก้ไขสำหรับ Django 2.2.x แต่วิธีแก้ปัญหาจาก Johnนั้นค่อนข้างฉลาด

รหัสปรับให้เข้ากับสถานการณ์ของฉันเล็กน้อย:

class NoteListInline(admin.TabularInline):
""" Notes list, readonly """
    model = Note
    verbose_name = _('Note')
    verbose_name_plural = _('Notes')
    extra = 0
    fields = ('note', 'created_at')
    readonly_fields = ('note', 'created_at')

    def has_add_permission(self, request, obj=None):
    """ Only add notes through AddInline """
    return False

class NoteAddInline(admin.StackedInline):
    """ Notes edit field """
    model = Note
    verbose_name = _('Note')
    verbose_name_plural = _('Notes')
    extra = 1
    fields = ('note',)
    can_delete = False

    def get_queryset(self, request):
        queryset = super().get_queryset(request)
        return queryset.none()  # no existing records will appear

@admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
    # ...
    inlines = (NoteListInline, NoteAddInline)
    # ...

0

คุณสามารถทำได้โดยการแทนที่เมธอด 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)

0

มีปัญหาที่คล้ายกัน ฉันแก้ไขด้วย "add_fieldsets" และ "restricted_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

โซลูชันที่เสียบได้มากขึ้นสำหรับโซลูชันที่ยอดเยี่ยมของ Bernhard และ Mario ซึ่งเพิ่มการสนับสนุนสำหรับ createonly_fields analog ไปยัง readonly_fields:

class MyModelAdmin(admin.ModelAdmin):

    # ModelAdmin configuration as usual goes here

    createonly_fields = ['title', ]

    def get_readonly_fields(self, request, obj=None):
        readonly_fields = list(super(MyModelAdmin, self).get_readonly_fields(request, obj))
        createonly_fields = list(getattr(self, 'createonly_fields', []))
            
        if obj:  # editing an existing object
            readonly_fields.extend(createonly_fields)
        return readonly_fields
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.