I've seen bits and pieces of this, but am having trouble putting it all together. Let's say I have a model with a field:
class MyModel(models.Model):
my_field = models.CharField(...)
And I want to remove all of the "x's" from my_field and save it:
def clean(self):
x_less = self.my_field.replace('x', '')
How do I get x_less to the save method? or how does the cleaned data get saved?
def save(self, *args, **kwargs):
self.my_field = x_less #??????
super().save(*args, **kwargs)
If there is a good tutorial that I missed somewhere, please let me know. Thanks.
Update:
You have to return from your clean method:
def remove_x(self):
x_less = self.my_field.replace('x', '')
return x_less
And assign the returned value in the save method:
def save(self, *args, **kwargs):
self.my_field = self.remove_x()
super().save(*args, **kwargs)
Old answer, but still useful
Letting the user provide some input and later change that input without a previous warning it will result in bad user experience.
Following your example use case: If you don't want xs to be in your input, provide a validator for that field:
def x_validator(value):
if 'x' in value:
raise ValidationError(
"x character is no allowed.",
params={'value': value}
)
class MyModel(models.Model):
my_field = models.CharField(validators=[x_validator], ...)
Said that, if you want to modify a model instance just before or after being saved. Take a look in to pre_save and post_save signals.
Related
i have two integer fields that i want to divide to get the value of 3rd field.
#property
def Pallets_Count(self):
return self.CASES/self.CasesPerPallet
but the result in the database always shows null .
#property
def Pallets_Count(self):
return self.CASES/self.CasesPerPallet
#property will not save anything into your model field. It works like a method. You can call in in your template like a model field mypost.Pallets_Count.
If you want to put the result into a database field, you need to override save method. But this might not be necessary. Property most likely is enough.
class MyModel(models.Model):
# your other fields
fieldname = models.FloatField()
def save(self, *args, **kwargs):
self.fieldname = self.CASES/self.CasesPerPallet
super(MyModel, self).save(*args, **kwargs)
I need to check if other models already created, have a field filled .
If another model has the field with any value, the current model that attempts to create should not happen. And if possible send an error message.
This is my current code:
class Video(models.Model):
#####
# Fields of model
#####
def save(self, force_insert=False, force_update=False, *args, **kwargs):
some_video = Video.objects.all().filter(field_boolean=True).first()
if not some_video:
# Save current model
super(Video, self).save(force_insert, force_update, *args, **kwargs)
else:
# avoid save method for the current model created and send error message
What am I doing wrong or what I'm missing? What is the correct way to do this?
Firstly, you do not need to use all() and filter() together. Secondly, use exists() instead of first(). It returns True if the QuerySet contains any results, and False if not. This tries to perform the query in the simplest and fastest way possible.
class Video(models.Model):
name = models.CharField(max_length=30)
field_boolean = models.BooleanField()
def __str__(self):
return self.name
def save(self, *args, **kwargs):
if Video.objects.filter(field_boolean=True).exists():
print('Video with field_boolean=True exists')
else:
super(Video, self).save(*args, **kwargs)
I have an attribute on a model that I don't want another developer to be able to go into the Django shell and change. Anyone know how to do this? I tried overwriting the save method on that model but I can't determine if that attribute has been changed.
Well I figured out how to accomplish this. Another developer could always change the code but this raises an error saying that's not what they're supposed to do.
class myModel(models.Model):
uuid = UUIDField('UUID', primary_key=True, default=uuid4)
model_type = models.ForeignKey(ModelType)
# override the Press model __init__ method to store initial press_type
def __init__(self, *args, **kwargs):
super(myModel, self).__init__(*args, **kwargs)
self.__model_type = self.model_type
# override the save method to prevent updates to press_type
def save(self, *args, **kwargs):
# raise an exception if press_type was changed since initialized
if self.pk and self.__model_type != self.model_type:
raise Exception('The model_type field cannot be changed once set.')
super(myModel, self).save(*args, **kwargs)
I have a model called Fattura, and I would like to set the default value of the field "printable" to a string that includes the value of the field "numero".
But I have the error that link_fattura has less arguments, but if I add default=link_fattura(self) I have an error because self is not defined.
How can I solve this issue?
class Fattura(models.Model):
def link_fattura(self, *args, **kwargs):
return u"http://127.0.0.1:8000/fatture/%s/" % (self.numero)
data = models.DateField()
numero = models.CharField("Numero", max_length=3)
fatturaProForma = models.ForeignKey(FatturaProForma)
printable = models.CharField("Fattura stampabile", max_length=200, default=link_fattura)
def __unicode__(self):
return u"%s %s" % (self.data, self.numero)
class Meta:
verbose_name_plural = "Fatture"
ordering = ['data']
You can't do this using the default argument. The best bet is to override the save method:
def save(self, *args, **kwargs):
if not self.id and not self.printable:
self.printable = self.link_fattura()
return super(Fattura, self).save(*args, **kwargs)
Sorry I read you question wrong, that's not possible without javascript because your model hasn't been saved at that stage yet.
You could forecast the url by doing something like:
def link_facttura(self):
if not self.id:
return some_url/fattura/%d/ % Fattura.objects.latest().id+1
return u""
But it's ugly and likely to cause erros once you start deleting records
Suppose I have a set of records which I know to be unique based on some other record and an e-mail, thusly:
class Signup(models.Model):
activity = models.ForeignKey(Activity, related_name='activities')
name = models.CharField(max_length=100)
email = models.EmailField()
# many addtional fields here not relevant to question
Then, I have a model form:
class SignupForm(forms.ModelForm):
class Meta:
model = Signup
exclude = [ 'activity' ]
def __init__(self, *args, **kwargs):
self.activity = kwargs.pop('activity')
def save(self, *args, **kwargs):
kwargs['commit'] = False
m = super(SignupForm, self).save(*args, **kwargs)
m.activity = self.activity
m.save()
return m
Suppose a user goes in a fills out the form under the activity, then realizes they made an error in the form, clicks the back button, makes changes, then clicks submit again.
Without any modifications to the code above, a duplicate record for that activity and email would be created.
What I want to know is how I can force the form to update, rather than create, a record if it finds a match for the entered e-mail.
I tried this code:
class SignupForm(forms.ModelForm):
class Meta:
model = Signup
exclude = [ 'activity' ]
def __init__(self, *args, **kwargs):
self.activity = kwargs.pop('activity')
def save(self, *args, **kwargs):
kwargs['commit'] = False
try:
self.instance = Signup.objects.get(email=self.cleaned_data['email'], activity=self.activity)
except Signup.DoesNotExist:
pass
m = super(SignupForm, self).save(*args, **kwargs)
m.activity = self.activity
m.save()
return m
However, looks like this causes the form to ignore all new information for some reason (I have debug toolbar running and examining the query confirms that none of the fields are being changed!)
Is there an accepted way of handling this?
Further request
Is there any way to do this while still using the ModelForm's built-in save function? So far the answers seem to suggest that this is impossible, which is, I'm sorry, ridiculous.
Replace
try:
self.instance = Signup.objects.get(email=self.cleaned_data['email'], activity=self.activity)
except Signup.DoesNotExist:
pass
With:
obj, created = Signup.objects.get_or_create(\
email=self.cleaned_data['email'],
activity=self.activity)
if created:
print 'its a new one, hooray!'
else:
print 'the object exists!'
More information on get_or_create.