Overriding the save method in Django ModelForm
In your save
you have to have the argument commit
. If anything overrides your form, or wants to modify what it's saving, it will do save(commit=False)
, modify the output, and then save it itself.
Also, your ModelForm should return the model it's saving. Usually a ModelForm's save
will look something like:
def save(self, commit=True):
m = super(CallResultTypeForm, self).save(commit=False)
# do custom stuff
if commit:
m.save()
return m
Read up on the save
method.Finally, a lot of this ModelForm won't work just because of the way you are accessing things. Instead of self.callResult
, you need to use self.fields['callResult']
.
UPDATE: In response to your answer:
Aside: Why not just use ManyToManyField
s in the Model so you don't have to do this? Seems like you're storing redundant data and making more work for yourself (and me :P
).
from django.db.models import AutoField
def copy_model_instance(obj):
"""
Create a copy of a model instance.
M2M relationships are currently not handled, i.e. they are not copied. (Fortunately, you don't have any in this case)
See also Django #4027. From http://blog.elsdoerfer.name/2008/09/09/making-a-copy-of-a-model-instance/
"""
initial = dict([(f.name, getattr(obj, f.name)) for f in obj._meta.fields if not isinstance(f, AutoField) and not f in obj._meta.parents.values()])
return obj.__class__(**initial)
class CallResultTypeForm(ModelForm):
callResult = ModelMultipleChoiceField(queryset=CallResult.objects.all())
campaign = ModelMultipleChoiceField(queryset=Campaign.objects.all())
callType = ModelMultipleChoiceField(queryset=CallType.objects.all())
def save(self, commit=True, *args, **kwargs):
m = super(CallResultTypeForm, self).save(commit=False, *args, **kwargs)
results = []
for cr in self.callResult:
for c in self.campain:
for ct in self.callType:
m_new = copy_model_instance(m)
m_new.callResult = cr
m_new.campaign = c
m_new.calltype = ct
if commit:
m_new.save()
results.append(m_new)
return results
This allows for inheritance of CallResultTypeForm
, just in case that's ever necessary. Override the save() method in Django ModelForm to create or update
Use django queryset get_or_create()
method.
From the docs: This method is used for looking up an object with the given kwargs (may be empty if your model has defaults for all fields), creating one if necessary.
Read more about it here in the docs.
Now, inside your view:
class ReviewFollowAuthor(View):
def post(self, request, **kwargs):
user = request.user
author = get_object_or_404(Author, id=kwargs['pk'])
#MAKE certain that user and author always have an instance within them.
#send the user, author to the form.
f = ReviewFollowAuthorForm(request.POST , user = user , author = author)
if(f.is_valid()):
f.save(user=user,userx=userx)
return JsonResponse({'success':1})
else:
return JsonResponse({'success':0})
Now, inside your ModelForm:class ReviewFollowAuthorForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
#override __init__ to make your "self" object have the instances sent by the your views.(author and user)
self.user = kwargs.pop('user' , None)
self.author = kwargs.pop('author' , None)
#Now your model-form instance has the user and the author attribute within itself.
super(ReviewFollowAuthorForm, self).__init__(*args, **kwargs)
class Meta:
model = UserAuthor
fields = ("is_follow", "review")
def save(self, commit=True):
user_author, created = UserAuthor.objects.update_or_create( user=self.user, author=self.author, defaults={'is_follow': self.cleaned_data.get('is_follow'), 'review': self.cleaned_data.get('review')} )
#rest of your logic
return user_author
I Hope this guides you in some way.Thanks.
Overriding Django ModelForm save method and deleting old values(files)
Try using this, it works just fine in terms of auto deleting old files and pictures.
https://pypi.org/project/django-cleanup/
Django save() overriding, best practice: on model, form or view?
Upon digging in the source code I found the ModelForm's save()
method to be calling the Model's(Model Instance) save()
method. Check it here.
Now it is clear that first ModelForm's save()
is called and within it(depending upon the commit value) Model's save()
is called.
Also it's worth noting that in the code:
def save(self, commit = True):
user = super(RegisterForm, self).save(commit = False)
user.set_password(self.cleaned_data["password1"])
#When you're hashing and setting the password to the user variable,
#this user variable is a Model Object but is not saved in the database yet.
if commit:
user.save()
#Now in the above line you're ultimately calling the save method of Model instance.
return user
So the question comes down to you. Do you want to go one more step above in the abstraction layers(by overriding Model instance's save method) of django models?
Do you actually have a need to do it?
Abstraction is one of the building block of OOPS. So until a need arises which actually requires you to go above in the abstraction layers, why do it at all? Clearly the password can be hashed in the ModelForm's save()
method.
Also, if you go a layer above in abstraction,
what if an unexpected behavior occurs in the future?
In my opinion, why not just leave it inside the ModelForm? We start from the highest layer of Abstraction when we start using django(we just call the methods and usually don't know what's happening in the classes we're inheriting; that's what oops is for) and we go above only when a specific need arises.
Hope this guides you in some way. Thanks.
override the save method in django
You can try a signal like this:
from django.dispatch import receiver
from django.db.models.signals import pre_save
from django.utils import timezone
@receiver(pre_save, sender=Product)
def update_create_field(sender, instance, **kwargs):
try:
_pre_save_instance = Product.objects.get(pk=instance.pk)
if _pre_save_instance.price != instance.price:
instance.create = timezone.now() #here you can specify any value you want
except Exception as e:
print('Error updating create field!')
print(e)
Related Topics
How to Use Numpy.Correlate to Do Autocorrelation
Difference Between Variable and Get_Variable in Tensorflow
Cannot Redirect Output When I Run Python Script on Windows Using Just Script's Name
How to Test a Function with Input Call
Pip: How to Install a Git Pull Request
Weighted Standard Deviation in Numpy
Splitting List Based on Missing Numbers in a Sequence
What Is More 'Pythonic' for 'Not'
Typeerror: Expected String or Buffer
Rotating a Two-Dimensional Array in Python
Pandas Latitude-Longitude to Distance Between Successive Rows
Does Python Evaluate If's Conditions Lazily
Setting Up S3 for Logs in Airflow
Looping from 1 to Infinity in Python
Is There an Platform Independent Equivalent of Os.Startfile()