I would like to write a custom update method for my model.
Basically I would like to make sure that the fields that being passed to this method are fields that are present in this model.
I came up with something like this
def update(self,dict):
#Check if the fields in this data are present in this model
for key in data:
if not hasattr(self, key):
#This property is not present
data.pop(key)
self.update(data)
However when I do something like this
modelMyobject.objects.filter(xxxxx).update(**dict)
This method never gets called. Any suggestions on what I could do to fix this ?
You are running your model method in Querysets, so instead of that, try either:
for i in modelMyobject.objects.filter(xxxxx):
i.update(**dict)
Or writing Custom Django Model Manager.
Related
i'm writing an app with django and i need to change a specific model when
ever it been saved. i.e lets say i have a model A and a client want to save
changes to that model - i need to also save a change (only if the client
changed a certain field) to the same model (not instance).
my code:
#receiver(pre_save, sender=A)
def my_callable(sender, instance, **kwargs):
a = A.objects.filter(b=True).all()
for my_a in a:
my_a.b= False
my_a.save()
i have 2 problems with that code:
it has an infinite recursion
i don't know how to check which field had changed
and ideas?
Use .update(b=False) on the queryset:
#receiver(pre_save, sender=A)
def my_callable(sender, instance, **kwargs):
A.objects.filter(b=True).update(b=False)
The update is done in SQL, doesn't call model's save() method or trigger any signals
.update() docs
Assuming you're able to use Django1.8, this exact use case is covered in the docs actually: https://docs.djangoproject.com/en/1.8/ref/models/instances/#customizing-model-loading
Cliff notes: use the from_db method to customize loading of the model and save a copy of the instance's attributes as it is loaded, and then compare them before it is saved.
If you want to compare form data to a model instance to see if a user is changing it, do that in the view, not with a signal.
I think I have a pretty common use case and am surprised at how much trouble it's giving me.
I want to use a key-value pair for a ReferenceField in the Flask-Admin edit form generated by the following two classes:
class Communique(db.Document):
users = db.ListField(db.ReferenceField(User), default=[])
class User(db.Document):
email = db.StringField(max_length=255, required=True)
def __unicode__(self):
return '%s' % self.id
I want the select to be constructed out of the ObjectId and the an email field in my model.
By mapping the __unicode__
attribute to the id field I get nice things on the mongoengine side like using the entire object in queries:
UserInformation.objects(user=current_user)
This has the unfortunate effect of causing the Flask-Admin form to display the mongo ObjectId in the edit form like so:
The docs say I have to provide the label_attr to the ModelSelectMultipleField created by Flask-Admin. I've done so by overriding the get_form method on my ModelView:
def get_form(self):
form = super(ModelView, self).get_form()
form.users = ModelSelectMultipleField(model=User,
label_attr='email',
widget=form.users.__dict__['kwargs']['widget'])
return form
I'm reusing the the widget used by the original form.users (which may be wrong). It works fine when editing an existing item, BUT throws an exception when creating a new one (perhaps because I'm reusing the widget).
All of this seems like way more work than should be needed to simply provide a label_attr to my SelectField. Fixing up the listing view was a simple matter of adding an entry to the column_formatters dictionary. Is there no simple way to specify the label_attr when creating my ModelView class?
I know I could make this problem go away by returning the email property in the __unicode__ attribute, but I feel like I shouldn't have to do that! Am I missing something?
Oy, now I see how to do it, though it's not that obvious from the docs. form_args is a dictionary with items keyed to the form models. All I needed to do was...
form_args = dict(users=dict(label_attr='email'))
Which does seem about the right amount of effort (considering Flask-Admin isn't some sort of java framework).
A form generates a list of all available foreign key elements. They are displayed depending on the __str__ function defined in the model.
I don't know how to search for this, but need to change this without touching the model.
My model connects with the User model. This model shows the username, but i would like to call the _get_full_name function to get a better list.
class Trainer(models.Model):
user=models.OneToOneField(User)
Is it possible to define it inside the definition of the Foreignkey or inside the model which connects (in my example the Trainer model)?
This should work:
def user_new_unicode(self):
return self.get_full_name()
User.__unicode__ = user_new_unicode #or User.__str__ = user_new_unicode
Of course it should be placed in your class.
Answer
As Sergey pointed out, class Model(**kwargs) is invalid, and is a typo in Django documentation.
The "class" part comes from the markup they used when they wrote it.
So, what they actually meant in the Django documentation is:
Creating objects
To create a new instance of a model, just instantiate it like any
other Python class:
Model(**kwargs)
The keyword arguments are simply the names of the fields you’ve
defined on your model. Note that instantiating a model in no way
touches your database; for that, you need to save().
Original question
I found the following while reading the Django Docs about Model instances:
Creating objects
To create a new instance of a model, just instantiate it like any
other Python class:
class Model(**kwargs)
The keyword arguments are simply the names of the fields you’ve
defined on your model. Note that instantiating a model in no way
touches your database; for that, you need to save().
What is the difference between these two codes?
class Model(**kwargs)
new_model = Model(**kwargs)
I know the second one creates a new instance of the class Model, with kwargs.
Is the first one different from it? To me, it seems like it rather redefines the Model class.
class Model(**kwargs) is not a valid Python syntax, the latter would look like
class Model(SomeBaseClass):
pass
Judging by the formatting (the line looks like a subheading), this must be a mistake in the Django documentation.
If you look at the Sphinx source of the page, you'll see that the "class" thing is actually a part of Sphinx markup. What they meant is
To create a new instance of a model, just instantiate it like any
other Python class:
Model(**kwargs)
The keyword arguments are simply the names of the fields you've
defined on your model.
The first line defines a class.
The second line defines an instance of a class.
I have a situation where I need to notify some users when something in DB changes. My idea is to catch pre_save and post_save signal and make some kind of diff and mail that. Generally it works good, but I don't know how to get diff for m2m fields.
At the moment I have something like this:
def pre_save(sender, **kwargs):
pk = kwargs['instance'].pk
instance = copy.deepcopy(sender.objects.get(pk=pk))
tracking[sender] = instance
def post_save(sender, **kwargs):
instance = copy.deepcopy(kwargs['instance'])
print diff(instance, (tracking[sender])) # TODO: don't print, save diff somewhere
Diff function should work for every model (at the mommet I have four model classes). With deepcopy I can save old model, but I don't know how to save m2m fields because they are in separate table (yes, I know I can get this data, but at the momment of execution I don't know what fields are m2m and I wouldn't like to create different slot for every model). What I would like is generic solution, so I can just add models later without thinking about notification part.
My plan is to call get_data() and clear_data() functions after save() in view to clean diff that slots have generated.
Is this good way of doing this? Is there a better way? Is there django application that can do this job for me?
Excuse my English, it's not my native language.
First of all, you don't need to use deepcopy for this. Re-querying the sender from the database returns a "fresh" object.
def pre_save(sender, **kwargs):
pk = kwargs['instance'].pk
instance = sender.objects.get(pk=pk)
tracking[sender] = instance
You can get a list of all the many-to-many fields for a class, and check the values related to the current instance:
for field in sender._meta.local_many:
values = field.value_from_object(instance).objects.all()
# Now values is a list of related objects, which you can diff