django admin, obj'i değiştirirken bir alanı salt okunur yapar, ancak yeni obj eklerken gereklidir


91

Yönetici olarak, nesneyi değiştirirken bir alanı devre dışı bırakmak istiyorum, ancak yeni nesne eklerken bunu zorunlu kılmak istiyorum.

Bunun için django'nun yolu nedir?

Yanıtlar:


180

Yöneticinin get_readonly_fieldsyöntemini geçersiz kılabilirsiniz :

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
Küçük / büyük uyarı: Bu, satır içi için çalışmaz. Dinamik "başka bir X ekle" düğmesi, beklediğiniz gibi bir form alanı değil, salt okunur alanı "(Yok)" olarak gösterir.
Cerin

17

Tüm alanları sadece değişiklik görünümünde salt okunur olarak ayarlamak istiyorsanız , yöneticinin get_readonly_fields değerini geçersiz kılın:

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

Ve değişikliğin görünümünde düğmeler tasarruf postu istiyorsanız :

  1. Görünümü değiştir

    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. Kullanıcı düzenlemeye çalışıyorsa izinleri değiştirin:

    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
    

    Bu çözüm Django 1.11 üzerinde test edilmiştir.


Mükemmel. Bu tam olarak ihtiyacım olan şey!
wogsland

3

Bilginize: Karşılaştığım aynı iki sorunla başka birinin karşılaşması durumunda:

  1. Readonly_fields sınıf özniteliğine doğrulamadan erişilebileceğinden, yine de sınıfın gövdesinde kalıcı olarak salt okunur alanları bildirmelisiniz (bkz. Django.contrib.admin.validation: validate_base (), satır.213 appx)

  2. Get_readonly_fields () 'a iletilen nesne ana nesne olduğu için bu, Inlines ile çalışmaz (css veya js kullanan oldukça hacky ve düşük güvenlikli çözümüm var)


2
2. nokta - bu, yöneticideki bir hatadan kaynaklanıyor: # 15602 Yakında düzeltilmeyecek gibi görünüyor (2 yıl önceki son etkinlik), bu yüzden CSS / JS çözümlerine bırakıldık.
frnhr

2

Bernhard Vallant'ın önceki mükemmel önerisine dayanan bir varyasyon, aynı zamanda temel sınıf tarafından sağlanan olası özelleştirmeleri de (varsa) korur:

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

Satır içi formlarla ilgili durum, Django 2.2.x için hala sabit değil, ancak John'un çözümü aslında oldukça akıllı.

Kod biraz durumuma göre ayarlanmış:

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

Bunu, ModelAdmin'in formfield_for_foreignkey yöntemini geçersiz kılarak yapabilirsiniz:

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

Benzer bir sorun var. Bunu ModelAdmin'de "add_fieldsets" ve "restricted_fieldsets" ile çözdüm.

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', )}),
             )

Lütfen örneğin bkz: http://code.djangoproject.com/svn/django/trunk/django/contrib/auth/admin.py

Ancak bu, modelinizi daha sonraki "add_objX" değişikliklerinden korumaz. Bunu da istiyorsanız, Model sınıfı "kaydetme" işlevini aşmanız ve oradaki değişiklikleri kontrol etmeniz gerektiğini düşünüyorum.

Bakınız: www.djangoproject.com/documentation/models/save_delete_hooks/

Selam, Nick

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.