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)
Related
I am screwed up to solve a problem for the last 7 days, yet I couldn't solve this problem! so much frustrated now!!!
I want when I create new GroupMess with an admin, the same admin should automatically add to members field,
this is my models:
class GroupMess(models.Model):
admin = models.OneToOneField(
User,
on_delete=models.CASCADE,
related_name='mess_admin'
)
members = models.ManyToManyField(User, related_name='mess_members', blank=True)
def save(self, *args, **kwargs):
self.members.add(self.admin)
super(GroupMess, self).save(*args, *kwargs)
If I try to create new GroupMess, it throws me this error:
"<GroupMess: GroupMess object (None)>" needs to have a value for field "id" before this many-to-many relationship can be used.
If i override save method like this:
def save(self, *args, **kwargs):
super(GroupMess, self).save(*args, *kwargs)
self.members.add(self.admin)
then it doesn't throw any error but the problem is, the members field remains blank
Can anyone help to fix this?
I want when I create GroupMess, I will add the admin during creating groupmess and the members filed should be filled automatically with the admin
*I mean, A group admin also will be a group member *
After you add the members to the Group model, save it again.
def save(self, *args, **kwargs):
super(Group, self).save(*args, **kwargs)
self.members.add(self.admin)
self.save()
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.
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 a model for which I would be able to set a value automatically before saving it to the database... so far I did override save() in this way:
def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
if not self.paramX:
self.paramX = value
super(Post, self).save(force_insert, force_update, using, update_fields)
Anyway, this does not work using bulk_create()... what can I do? (I'm trying using Signals but with no luck)
Extract from the documentation : (https://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.bulk_create)
The model’s save() method will not be called, and the pre_save and post_save signals will not be sent.
It is because the bulk saving method use an other way to save the data. And so a way is to manually do it as you create each entry to insert.
My preference would be the following:
class Instrument(models.Model):
name = models.CharField(max_length=20)
def __init__(self, *args, **kwargs):
super(Instrument, self).__init__(*args, **kwargs)
self.name = "Bass"
Edit:
I just re-read your question. If you're only concerned with whether or not the “paramX” field is set upon saving, couldn't you just add a “default” to the model field? i.e.
class Instrument(models.Model):
name = models.CharField(max_length=20, default="No instrument")
What it says on the tin. Is there a way to make a Django model read-only?
By this I mean a Django model in which once records have been created, they can't be edited.
This would be useful for a model that records transaction history.
You can override the model's save method and check whether it's an existing entity, in which case you won't save any changes:
def save(self, *args, **kwargs):
if self.id is None:
super(ModelName, self).save(*args, **kwargs)
So in this example you only save the changes when the entity has not got an id yet, which is only the case when it's a new entity that hasn't been inserted yet.
You can override the save method and not call super if you wanted to. That'd be a fairly easy way of accomplishing this.
# blatantly ripped the save from another answer, since I forgot to save original model
def save(self, *args, **kwargs):
if self.id is None:
super(ModelName, self).save(*args, **kwargs)
def delete(self, *args, **kwargs):
return
You should probably also raise an exception if a delete or update is attempting to occur instead of simply returning. You want to signal the user what is happening - that the behaviour isn't valid.
In addition to other solutions: If your main goal is to avoid write access from the admin, you can modify the used admin class so that nobody has an add/change permission:
class HistoryAdmin(admin.ModelAdmin):
def has_add_permission(self, request):
return False
def has_change_permission(self, request, obj=None):
return False
def has_delete_permission(self, request, obj=None):
return False
If you don't want an attempt to modify a record to fail silently:
def save(self, *args, **kwargs):
if self.pk:
(raise an exception)
super(YourModel, self).save(*args, **kwargs)
def delete(self, *args, **kwargs):
(raise an exception)