Django : Know if property is the default value - django

How can you know if a value is the default value for a Model's property.
For example
class Alias(models.Model) :
image = models.ImageField(upload_to='alias', default='/media/alias-default.png')
a = Alias.get("123")
# this doesn't work
if a.image == a.image.default :
pass
# nor this
if a.image == Alias.image.default :
pass
I tried digging in the docs, but didn't see anything.

You can't get it from the property itself, you have to go via the model options under model._meta.
a._meta.get_field_by_name('image')[0].get_default()

The default in Django is not the same as SQL default - it's there merely for admin to auto-fill the form field on new object creation.
If you want to compare something to value defined as default you have to define it somewhere else (i.e. in settings.py). Like:
class MyModel(models.Model):
...
my_field = models.IntegerField(default=settings.INT_DEFAULT)
The default value is stored in MyModel._meta._fields()[field_creation_index].default but be aware that this is digging in internals.

Related

creating object of a class that has keyword arguments at runtime in python

I am using mongoengine in python as an ORM. Now I have a situation where I have a class, actually the a model, of the form:
from mongoengine import *
class SomeDetails(Document):
alias = StringField(required=True)
version = StringField(required=True)
author = StringField(required=True)
someName = StringField(required=True)
Now I need to create the object of this class (and hence a document at runtime)
I can create an object of a normal class at runtime by using inspection, something like this:
from inspect import isclass
# moduleImport is a method made to facilitate importing of modules at runtime.
new_module = moduleImport('myModule')
classes = [x for x in dir(new_module) if isclass(getattr(new_module, x))]
class_object = getattr(new_module, classes[0])
instance = class_object()
And the above works perfectly. I am able to create an object at runtime and then use it as I wish.
However, in the former case above, when I need to create an object (or actually a mongo document in this case), as per the mongoengine documentation here and here, I need to create the object something like this:
docObject = SomeDetails(alias=value, version=value, author=value, someName=value)
docObject.save() # to save the document in the mongodb
wherein I need to specify the values for each of the keyword arguments while creating the object of the class, so that the document gets saved successfully.
So in this case, if I try creating the object of the SomeDetails class at runtime (as shown in the inspect example above) how can I provide these keyword arguments at the runtime while creating the object?
An important catch
So the keyword arguments are also not known before hand. They too are fetched at runtime. At runtime, before object creation, yes, I do know the list of keyword args and it's values, which is available to me as a dictionary as :
{alias:"a", version:"b", author:"c", someName:"d"}
but even then, this dic itself is available only at runtime.
You can try this:
data = {alias:"a", version:"b", author:"c", someName:"d"}
instance = class_object(**data)
More on **kwargs here
Presumably, you would just replace the line
instance = class_object()
With
instance = class_object(alias="a", version="b", author="c", someName="d")
If this doesn't work, please elaborate on what error you get.

Detect if a newly created model has changed attributes

Say you have a /new route, and the router creates a new instance of your model.
Your model's properties are bound to some input fields on the page.
I want to be able to detect if the new model has changed since it's instantiation.
model.get('hasDirtyAttributes') unfortunately reports true for new instances, because it has not been saved yet.
I thought to try model.get('hasDirtyAttributes') && model.get('dirtyType') === 'updated' but dirtyType is still created until you do the first save.
You can call model.changedAttributes() and see if it's empty (docs), but you can't observe it. Ex -
Object.keys(this.get('model').changedAttributes()).length > 0
I am not aware of a general attribute that you could observe in this case. You would have to observe a specified list of attributes.
or you could override set on your model and have it set a value -
set: (key, value) ->
#attributeHasChanged = true
#_super(key, value)
You could create a computed property on that model which would depend on any declared attribute and would return true if any of attributes differs from it's initial value, otherways false.
For better performance you could only compute this property if model.get('isNew') === true.

Django: How to access the model id's within an AJAX script?

I was wondering what is the correct approach,
Do I create HiddenInput fields in my ModelForm and from the
View I pass in the primaryKey for the models I am about to edit into
the hiddenInput fields and then grab those hiddenInput fields from
the AJAX script to use it like this?
item.load(
"/bookmark/save/" + hidden_input_field_1,
null,
function () {
$("#save-form").submit(bookmark_save);
}
);
Or is there is some more clever way of doing it and I have no idea?
Thanks
It depends upon how you want to implement.
The basic idea is to edit 1. you need to get the existing instance, 2. Save provided information into this object.
For #1 you can do it multiple ways, like passing ID or any other primary key like attribute in url like http://myserver/edit_object/1 , Or pass ID as hidden input then you have to do it through templates.
For #2, I think you would already know this. Do something like
inst = MyModel.objects.get(id=input_id) # input_id taken as per #1
myform = MyForm(request.POST, instance=inst)
if myform.is_valid():
saved_inst = myform.save()
I just asked in the django IRC room and it says:
since js isn't processed by the django template engine, this is not
possible.
Hence the id or the object passed in from django view can't be accessed within AJAX script.

How to set django model field by name?

This seems like it should be dead simple, so I must be missing something. I just want to set the value of a field in my model instance by name. Say I have:
class Foo(Model):
bar = CharField()
f = Foo()
I want to set the value of bar by name, not by accessing the field. So something like:
f.fields['bar'] = 'BAR"
instead of
f.bar = 'BAR'
I've tried setattr but it doesn't persist the value in the database. I also tried going through _meta.fields but got various errors along the way.
If you modify the value via setattr, you need to remember to save the model after modifying it. I've been bitten in the past where I changed the values but forgot to save the model, and got the same result.
setattr(f, 'bar', 'BAR')
f.save()
We may have to see more code.
setattr(f, 'bar', 'BAR')
should work as this is how Django does it internally.
Make sure you are calling 'save', as well.

How do I get the default value for a field in a Django model?

I have a Django model with some fields that have default values specified. I am looking to grab the default value for one of these fields for us later on in my code. Is there an easy way to grab a particular field's default value from a model?
TheModel._meta.get_field('the_field').get_default()
As of Django 1.9.x you may use:
field = TheModel._meta.get_field('field_name')
default_value = field.get_default()
You can get the field like this:
myfield = MyModel._meta.get_field_by_name('field_name')
and the default is just an attribute of the field:
myfield.default
if you don't want to write the field name explicitly, you can also do this:
MyModel._meta.get_field(MyModel.field.field_name).default
If you need the default values for more than one field (e.g. in some kind of reinitialization step) it may be worth to just instantiate a new temporary object of your model and use the field values from that object.
temp_obj = MyModel()
obj.field_1 = temp_obj.field_1 if cond_1 else 'foo'
...
obj.field_n = temp_obj.field_n if cond_n else 'bar'
Of course this is only worth it, if the temporary object can be constructed without further performance / dependency issues.