En administrateur, je voudrais désactiver un champ lors de la modification d'un objet, mais le rendre obligatoire lors de l'ajout d'un nouvel objet.
Quelle est la manière django de traiter celui-ci?
django
django-admin
frnhr
la source
la source
Si vous souhaitez définir tous les champs en lecture seule uniquement dans la vue des modifications, remplacez les champs get_readonly_fields de l'administrateur:
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
Et si vous souhaitez masquer les boutons d'enregistrement lors de la modification de la vue :
Changer la vue
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)
Modifiez les autorisations si l'utilisateur tente de modifier:
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
Cette solution a été testée sur Django 1.11
la source
FYI: au cas où quelqu'un d'autre rencontrerait les deux mêmes problèmes que j'ai rencontrés:
Vous devez toujours déclarer tous les readonly_fields en permanence dans le corps de la classe, car l'attribut de classe readonly_fields sera accessible à partir de la validation (voir django.contrib.admin.validation: validate_base (), line.213 appx)
Cela ne fonctionnera pas avec Inlines car l'obj passé à get_readonly_fields () est l'obj parent (j'ai deux solutions plutôt hacky et peu sécurisées utilisant css ou js)
la source
Une variation basée sur l'excellente suggestion précédente de Bernhard Vallant, qui préserve également toute personnalisation possible fournie par la classe de base (le cas échéant):
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
la source
La situation avec les formulaires en ligne n'est toujours pas corrigée pour Django 2.2.x mais la solution de John est en fait assez intelligente.
Code légèrement adapté à ma situation:
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) # ...
la source
Vous pouvez le faire en remplaçant la méthode formfield_for_foreignkey de 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)
la source
Vous avez un problème similaire. Je l'ai résolu avec "add_fieldsets" et "restricted_fieldsets" dans 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', )}), )
Veuillez consulter par exemple: http://code.djangoproject.com/svn/django/trunk/django/contrib/auth/admin.py
Mais cela ne protège pas votre modèle des modifications ultérieures de "add_objX". Si vous voulez cela aussi, je pense que vous devez passer par la fonction "save" de la classe Model et y vérifier les changements.
Voir: www.djangoproject.com/documentation/models/save_delete_hooks/
Greez, Nick
la source