No admin, gostaria de desativar um campo ao modificar um objeto, mas torná-lo obrigatório ao adicionar um novo objeto.
Qual é o jeito do django de fazer isso?
django
django-admin
frnhr
fonte
fonte
Se você deseja definir todos os campos como somente leitura na visualização de alteração, substitua os get_readonly_fields do administrador:
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
E se você deseja ocultar os botões de salvar na visualização de mudança :
Mudar a vista
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)
Altere as permissões se o usuário estiver tentando editar:
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
Esta solução foi testada no Django 1.11
fonte
Para sua informação: caso outra pessoa tenha os mesmos dois problemas que eu encontrei:
Você ainda deve declarar qualquer readonly_fields permanentemente no corpo da classe, já que o atributo de classe readonly_fields será acessado a partir da validação (veja django.contrib.admin.validation: validate_base (), line.213 appx)
Isso não funcionará com Inlines já que o obj passado para get_readonly_fields () é o obj pai (eu tenho duas soluções bastante hacky e de baixa segurança usando css ou js)
fonte
Uma variação baseada na excelente sugestão anterior de Bernhard Vallant, que também preserva qualquer personalização possível fornecida pela classe base (se houver):
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
fonte
A situação com os formulários embutidos ainda não foi corrigida para Django 2.2.x, mas a solução de John é realmente muito inteligente.
Código ligeiramente ajustado à minha situação:
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) # ...
fonte
Você pode fazer isso substituindo o método formfield_for_foreignkey do 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)
fonte
Tenho um problema semelhante. Resolvi isso com "add_fieldsets" e "restricted_fieldsets" no 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', )}), )
Consulte, por exemplo: http://code.djangoproject.com/svn/django/trunk/django/contrib/auth/admin.py
Mas isso não protege seu modelo de mudanças posteriores de "add_objX". Se você quiser isso também, acho que você tem que passar pela função "salvar" da classe Model e verificar as alterações lá.
Consulte: www.djangoproject.com/documentation/models/save_delete_hooks/
Greez, Nick
fonte
Uma solução mais plugável para as grandes soluções de Bernhard e Mario, adicionando suporte para analog createonly_fields para 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
fonte