J'essaie de remplacer la méthode save_model sur un Django admin object pour empêcher un utilisateur de changer un certain champ. Cependant, je ne trouve pas de moyen de trouver si le champ a changé dans cette méthode.
Voici mon code jusqu'à présent:
def save_model(self, request, obj, form, change):
if change:
if obj.parking_location == form.cleaned_data['parking_location']:
super(MyVehiclesAdmin, self).save_model(request, obj, form, change)
else:
messages.error(request,
"The Parking Location field cannot be changed.")
Le problème est que obj.parking_location et form.cleaned_data ['parking_location'] ont la nouvelle valeur. (Cela pourrait-il être un bogue dans Django? Il semble vraiment que l'obj devrait contenir les valeurs de pré-sauvegarde). Dans tous les cas, existe-t-il un autre moyen d'y parvenir?
(Je suis sur Django 1.2)
Tout d'abord, ce n'est pas un bug, c'est le comportement documenté dans Django 1.2 et ultérieur.
Depuis les Notes de version de Django 1.2 :
la première fois que vous appelez
ModelForm.is_valid()
, accédez àModelForm.errors
ou autrement déclencher la validation du formulaire, votre modèle sera nettoyé sur place. Cette conversion se produisait lors de l'enregistrement du modèle. Si vous avez besoin d'une instance non modifiée de votre modèle, vous devez transmettre une copie au constructeur ModelForm.
Si vous voulez empêcher l'utilisateur de modifier un champ paticulaire, une meilleure approche pourrait être d'utiliser le ModelAdmin.readonly_fields
option.
class VehicleRegistrationAdmin(admin.ModelAdmin):
readonly_fields = ('parking_location',)
Vous pouvez également remplacer le ModelAdmin.form
avec un formulaire personnalisé qui exclut ce champ.
class VehicleRegistrationForm(forms.ModelForm):
class Meta:
exclude = ('parking_location',)
class VehicleRegistrationAdmin(admin.ModelAdmin):
form = VehicleRegistrationForm
Enfin, pour répondre plus directement à votre question, vous pouvez vérifier si un champ a changé dans le save_model
méthode en inspectant form.changed_data
. Ceci est une liste des noms des champs qui ont changé.
def save_model(self, request, obj, form, change):
if 'parking_location' in form.changed_data:
messages.info(request, "Parking location has changed")
else:
messages.info(request, "Parking location has not changed")
super(MyVehiclesAdmin, self).save_model(request, obj, form, change)
Pour ceux qui s'interrogent sur le paramètre change
:
Ce paramètre sera True s'il s'agit d'un changement sur un modèle existant, il est False si le modèle est une instance nouvellement créée.
Pour vérifier si des champs ont été modifiés: form.changed_data
contiendra les champs modifiés, ce qui signifie qu'il est vide s'il n'y a aucun changement.
vous pouvez toujours trouver la valeur de la base de données avec MyVehicles.objects.get(pk=obj.pk)
Ok, j'ai trouvé une solution. Cela me semble toujours être un bug.
def save_model(self, request, obj, form, change):
if change:
vr = VehicleRegistration.objects.get(pk=obj.id)
if vr.parking_location == form.cleaned_data['parking_location']:
super(MyVehiclesAdmin, self).save_model(request, obj, form, change)
else:
messages.error(request,
"The Parking Location field cannot be changed.")