How to execute a function when a variable's value is changed? - python-2.7

In Odoo 10, I want to change the value of a variable when the forecasted quantity of a product is changed. I tried using the #api.onchange decorator, but it doesn't work. The forecasted quantity change, but the variable keeps the same value. I have this:
class MyProduct(models.Model):
_inherit = 'product.product'
was_changed = fields.Boolean(default = False)
#api.onchange('virtual_available')
def qtychanged(self):
self.was_changed = True
_logger.info('Product_Qty_Cahnged: %s',str(self.virtual_available))
In this code, if the forecasted quantity of a product would change, the variable was_changed should be set to True, but nothing happens.
After that, I tried to overwrite the write method for my custom class, like this:
class MyProduct(models.Model):
_inherit = 'product.product'
was_changed = fields.Boolean(default=False)
#api.multi
def write(self, values):
if values['virtual_available']:
values['was_changed'] = True
# THE FOLLOWING LINES WERE IN THE ORIGINAL WRITE METHOD
res = super(MyProduct, self).write(values)
if 'standard_price' in values:
self._set_standard_price(values['standard_price'])
return res
But still, I have the same result. I can't seem to get that flag to change. So, any ideas?

Try this:
class MyProduct(models.Model):
_inherit = 'product.product'
was_changed = fields.Boolean(default = False)
#api.onchange('virtual_available')
def qtychanged(self):
self.write({'was_changed': True})
_logger.info('Product_Qty_Cahnged: %s',str(self.virtual_available))

Related

How to modify the form filed data?

I have a model:
class PastStudy(Model):
grade_average = FloatField(null=True)
I have a modelform as below:
class PastStudyForm(ModelForm):
class Meta:
model = PastStudy
fields = ('grade_average', )
What I have in view:
...
if request.POST:
past_study_form = PastStudyForm(request.POST)
if past_study_form.is_valid():
return HttpResponse(past_study_form.cleaned_data['grade_average'])
else:
profile_filter_past_study_form = ProfileFilterPastStudyForm()
...
What I need is that I want to write a clean method for PastStudyForm so that in case I entered 90 as grade average, HttpResponse converts it two 0-20 grading scheme and returns 18.
I tried this and I was still getting 90 not 18
class PastStudyForm(ModelForm):
class Meta:
model = PastStudy
fields = ('grade_average', )
def clean(self):
cleaned_data = super().clean()
grade_average = self.cleaned_data['grade_average']
self.cleaned_data['grade_average'] = grade_average/5
return cleaned_data
and This:
class PastStudyForm(ModelForm):
class Meta:
model = PastStudy
fields = ('grade_average', )
def clean_grade_average(self):
grade_average = self.cleaned_data['grade_average']
data = grade_average/5
return data
However, I still get 90. I also have tried a few other methods but I still was getting 90 in HttpResponse
Maybe using clean method be wrong and I should do something else!
The real code is huge and I have summarized it in here and other aspects of the problem are not explained in here. That is why I prefer and expect to get a response in which I am advised how to it in the form definition, not other methods such as converting it in the view.
in your clean method, you assign the result of your calculation method into self.cleaned_data,
while you are returning cleaned_data not self.cleaned_data.
it is different variable.
try this instead:
self.cleaned_data = super().clean()
grade_average = self.cleaned_data['grade_average']
self.cleaned_data['grade_average'] = grade_average/5
return self.cleaned_data

Call method on Django fields

class Colour(models):
...
def colour_preview(self):
return format_html(...)
class ColourTheme(models):
colour1 = models.ForeignKey(Colour)
colour2 = models.ForeignKey(Colour)
colour3 = models.ForeignKey(Colour)
...
def preview(self):
for field in self._meta.get_fields(include_parents=False):
if (field.related_model == Colour):
field.colour_preview()
I have a ColourTheme model with multiple Colour foreign keys, and I want to call a function on each of the Colour objects referred to by those fields. The last line of code above fails. I would like to call colour_preview on all Colour fields without hardcoding them (self.colour1.colour_preview() works but not ideal).
How might I achieve this?
You cannot refer to the field in order to access related object method.
Try something like this (I haven't tested it):
class ColourTheme(models):
colour1 = models.ForeignKey(Colour)
colour2 = models.ForeignKey(Colour)
colour3 = models.ForeignKey(Colour)
...
def preview(self):
for field in self._meta.get_fields(include_parents=False):
if (field.related_model == Colour):
field_obj = field.value_from_obj(self) # To get obj reference
field_obj.colour_preview()

Change a series I have been given

from sqlalchemy import Column, Integer, String, Boolean, Float, DateTime, ForeignKey
from sqlalchemy.orm import relationship, reconstructor
from app import utils
import datetime
import pandas
from base import Base
from series import Series
class ConstantSeries(Series):
__tablename__ = 'constantseries'
# ID Primary Key (linked to parent)
id = Column(Integer, ForeignKey('series.id'), primary_key=True)
# The value of this series to be returned for all periods.
value = Column(Float)
__mapper_args__ = {'polymorphic_identity': 'constantseries'}
def GetData(self, scenario, periods):
"""Get data values for the specified periods.
"""
return pandas.Series(data=[self.value]*len(periods), index=periods)
I have been given the code above but I want to be able to change it so that I can have a series that has different values depending on what day it is. For example if it is a weekday I have a value of 100 and for a weekend have a value of 200
Can you tell me how you are calling the above code and what it currently returns?
It seems that the GetData function just returns a data structure, i.e. it returns the structure of a Column for every period, but no actual data.
What's not shown here is how the actual data in the Columns is populated and accessed.
You could loop through your periods and build the Series data according to the day e.g if periods contained ['mon','tue','wed','thu','fri','sat','sun']
def GetData(self, scenario, periods):
mydata = {}
for p in periods:
if p in ['sat','sun']:
e[p] = 200
else:
e[p] = 100
return pandas.Series(mydata, index=periods)
Then calling GetData should return something like
'mon' 100
'tue' 100
...
'sat' 200
'sun' 200
but thats not the structure you want and i dont think its how the Getdata function is being used.
def GetData(self, scenario, periods):
rtn = {}
for timest, val in cap.GetData(base_scenario,utils.enumerate_periods(start,end,'H','CET')).iteritems():
if timest.weekday_name in ['Saturday', 'Sunday']:
rtn[timest.weekday_name] = (0.72 * val)
#0.46*2574
else:
rtn[timest.weekday_name] = (1.0 * val)
return [rtn]
#Define ConstantSeries class
#I have made no changes here, just what you already had
class ConstantSeries(Series):
__tablename__ = 'constantseries'
# ID Primary Key (linked to parent)
id = Column(Integer, ForeignKey('series.id'), primary_key=True)
# The value of this series to be returned for all periods.
value = Column(Float)
__mapper_args__ = {'polymorphic_identity': 'constantseries'}
def GetData(self, scenario, periods):
"""Get data values for the specified periods.
"""
return pandas.Series(data=[self.value]*len(periods), index=periods)
#End of class definition
#Define new special Cap2Series class
class Cap2Series(Series):
#I'm not sure how tablename is used so be aware, might need to put constantseries as before
__tablename__ = 'cap2series'
# ID Primary Key (linked to parent)
id = Column(Integer, ForeignKey('series.id'), primary_key=True)
# The value of this series to be returned for all periods.
value = Column(Float)
#Same as above, I'm not sure how this is used so be aware, might need to put constantseries as before
__mapper_args__ = {'polymorphic_identity': 'cap2series'}
#Define GetData method of our new special class
def GetData(self, scenario, periods):
#instantiate new ConstantSeries instance called cap when you call GetData
cap = (ConstantSeries(value=self.value))
rtn = {}
for timest, val in cap.GetData(scenario, periods).iteritems():
if timest.weekday_name in ['Saturday', 'Sunday']:
rtn[timest.weekday_name] = (0.72 * val)
#0.46*2574
else:
rtn[timest.weekday_name] = (1.0 * val)
return pandas.Series(data=rtn, index=periods)
#End of class definition
#Instantiate new Cap2Series instance called cap2
cap2 = Cap2Series(1647)
#Call GetData method of cap2 instance
cap2.GetData(base_scenario, utils.enumerate_periods(start,end,'H','CET')).plot()
#Is this something like what you're trying to do?

Computed Property for Google Datastore

I am not sure exactly how achieve this.
I have a model defined as
class Post(ndb.Model):
author_key = ndb.KeyProperty(kind=Author)
content = ndb.StringProperty(indexed=False)
created = ndb.DateTimeProperty(auto_now_add=True)
title = ndb.StringProperty(indexed=True)
topics = ndb.StructuredProperty(Concept, repeated=True)
concise_topics = ndb.ComputedProperty(get_important_topics())
#classmethod
def get_important_topics(cls):
cls.concise_topics = filter(lambda x: x.occurrence > 2, cls.topics)
return cls.concise_topics
I like to set the value of concise_topics (Which is on the same type as topics) to a subset acheived via get_important_topics method. This should happen the moment the topics property has been set.
How do I define the "concise_topics" property in the Post class ?
With class method, you don't have access to the instance values. And also you shouldn't call the function, only pass it to the computed property, and let it call by itself.
class Post(ndb.Model):
author_key = ndb.KeyProperty(kind=Author)
content = ndb.StringProperty(indexed=False)
created = ndb.DateTimeProperty(auto_now_add=True)
title = ndb.StringProperty(indexed=True)
topics = ndb.StructuredProperty(Concept, repeated=True)
def get_important_topics(self):
return filter(lambda x: x.occurrence > 2, self.topics)
concise_topics = ndb.ComputedProperty(get_important_topics)
As far as I remember the computed property is set on each put call, so your topics should be already there by that time.

How can I get a list from model for the template

in the models.py, I have a model which has a list attribute:
Class Controller(models.Model):
def controller(self):
result = []
#...do some works here...
result = xxx
Now I want to use the "result" attribute in the template, in views.py I have:
def results(request):
cmodel = Controller()
cmodel.controller()
firstList = get_list_or_404(Controller, 'I am not sure how to write this filter')
return render_to_response('blablabla/')
I am not sure how to write the filter, since the samples are giving something like "pk=1", but I don't have any primary keys or ids for the 'result' object. Can anyone help me? Thank you.
Your controller function should return result:
Class Controller(models.Model):
def controller(self):
result = []
#...do some works here...
result = xxx
return result # <----------
And then you can get it as:
c = Controller()
result_list = c.controller()
Is that what you want?