Reputation: 8312
I have an AdminModel that allows users to save with any of the fields left empty. However, I don't want them to be able to save when all fields are empty. I've implemented this using the following:
def save_model(self, request, obj, form, change):
if form.has_changed():
obj.save()
else:
pass
However, the Model has a M2M relationship with another Model, so I get the following error when I hit save:
instance needs to have a primary key value before a many-to-many relationship can be used.
What do I need to add to this method to stop it trying to create the M2M relationship?
Edit:
I've added hacky workaround, but I'd be interested in knowing if there's a better way of doing it. The workaround was to change the else
so it changes the ModelAdmin's field attribute so that it doesn't contain the field for the M2M relationship - this prevents it from trying to make the relationship. This is not only hacky, but also only works after it's failed to save the model once and thrown an error...
Upvotes: 0
Views: 255
Reputation: 53999
It would be best to do the validation at the form level instead of the admin level. To do this, create a custom Form
class to be used by your ModelAdmin
. So create a forms.py
:
from myapp.models import MyModel
from django import forms
class MyModelForm(forms.ModelForm):
pass
class Meta:
model = MyModel
def clean(self):
empty = True
for field_name, field_data in self.cleaned_data.iteritems():
if field_data:
empty = False
if empty:
raise forms.ValidationError("The form cannot be empty")
return self.cleaned_data
and allow your admin to use this form. In admin.py
:
from myapp.forms import MyModelForm
from django.contrib import admin
class MyModelAdmin(admin.ModelAdmin):
...
form = MyModelForm
Upvotes: 2
Reputation: 118488
You can't - save_m2m
is called after save_model
. The docs specifically say this hook is not for veto purposes.
ModelAdmin.save_model() and ModelAdmin.delete_model() must save/delete the object, they are not for veto purposes, rather they allow you to perform extra operations.
What you need is form validation to prevent save_model
from triggering. Somehow, you need to detect when all fields are left blank.
class MyForm(forms.ModelForm):
class Meta:
model = MyModel
def clean(self):
if not any(self.cleaned_data.values()):
raise forms.ValidationError("All fields cannot be blank!")
return self.cleaned_data
class MyAdmin(admin.ModelAdmin):
form = MyForm
Upvotes: 3