Before save model check some field - django

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)

Related

Trying to do a calculation on django models

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)

How does Django model save data that is cleaned?

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.

Prevent shell from saving attribute in Django

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)

ModelForm User Mixin

I've got some models with user field.
For this purpose I'd like to create a form mixin that would add self.user instance (which is provided to the form in views). Is it possible ?
Here's the example
class UserFormMixin(object):
"""Removes user instance from kwargs and adding it to object"""
def __init__(self, *args, **kwargs):
super(UserFormMixin, self).__init__(*args, **kwargs)
self.user = kwargs.pop('user')
def save(self, **kwargs):
obj = super(UserFormMixin, self).save(commit=False)
obj.user = self.user
if kwargs['commit']:
return obj.save()
else:
return obj
What I'd like to achieve:
class SomeFormWithUserField(UserFormMixin, ModelForm):
class Meta:
model = SomeModelWithUserField
fields = ['fields without user']
def save(self, **kwargs):
data = super(SomeFormWithUserField, sefl).save(commit=False)
#data already with user prepended
#do some other stuff with data
if kwargs['commit']:
return data.save()
else
return data
class SomeOtherFormWithUser(UserFormMixin, ModelForm):
class Meta:
model = SomeOtherModel
fields = ['some fields without user']
# no need to save here.. standard model form with user prepended on save()
The problem is that UserFormMixin doesn't know about model instance? Or am I wrong here?
I am getting some problems.. like 'commit' kwargs key error.. or object is not saved..
You're close, you just have some logic errors. First, in order to override ModelForm methods, your mixin needs to inherit from ModelForm.
class UserFormMixin(forms.ModelForm):
...
Then, any forms that inherit from it just inherit UserFormMixin, not ModelForm.
class SomeOtherFormWithUser(UserFormMixin):
...
Second, your __init__ method override is incorrect. You need to accept any and all args and kwargs that get passed into it.
def __init__(self, *args, **kwargs):
...
Finally, don't override the save method again, in the subclass. I guess it won't technically hurt anything, but what's the point of inheritance if you're going to repeat code, anyways? If user is not nullable, you can always add an if block to check if self.user is not None before adding it to the model. Of course, if user is not nullable, your model won't likely save without self.user anyways.
This one seems to work fine. Thanks Chris!
If this can be coded better please let me know.
class UserFormMixin(forms.ModelForm):
"""Removes user instance from kwargs and adding it to object"""
def __init__(self, *args, **kwargs):
super(UserFormMixin, self).__init__(*args, **kwargs)
self.user = kwargs.pop('user')
def save(self, commit=True):
obj = super(UserFormMixin, self).save(commit=False)
obj.user = self.user
if commit:
return obj.save()
else:
return obj
class SomeFormWithUserField(UserFormMixin):
class Meta:
model = SomeModelWithUserField
fields = ['fields without user']
def save(self, **kwargs):
data = super(SomeFormWithUserField, sefl).save(commit=False)
#data already with user prepended
#do some other stuff with data
# self.send_mail() f.e.
return data.save()
class SomeOtherFormWithUser(UserFormMixin):
class Meta:
model = SomeOtherModel
fields = ['some fields without user']
# this will work too

Django: accessing session variable while overriding model's save method

Is there any way to access sessions variables while overriding any models save method
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
def save(self, *args, **kwargs):
//Code for accessing session variable
super(Blog, self).save(*args, **kwargs)
Thanks,
not directly
you could add an extra argument to the save method and pop it off before calling the super save:
def save(self, *args, **kwargs):
request = kwargs.pop('request')
view...:
instance.save(request=request)
But
if you are saving a form it may be better to use
view...:
instance = form.save(commit=False)
# do some logic
instance.save()