Expression contains mixed types: SmallIntegerField, BigIntegerField. You must set output_field - django

I create a model in django
I want to set monthly_wage as monthly_wage=working_days*daily_wage in the annotation
from django.db.models import F
class AnnotationManager(models.Manager):
def __init__(self, **kwargs):
super().__init__()
self.annotations = kwargs
def get_queryset(self):
return super().get_queryset().annotate(**self.annotations)
class DetailsList(models.Model):
month_list=models.ForeignKey('MonthList',on_delete=models.CASCADE,verbose_name='لیست ماهانه ')
worker=models.ForeignKey('Workers',on_delete=models.CASCADE,verbose_name=' نام کارگر')
working_days=models.SmallIntegerField('تعداد روز کارکرد')
daily_wage=models.BigIntegerField('دستمزد روزانه')
advantage=models.BigIntegerField('مزایای ماهانه')
_monthly_wage=0
objects = AnnotationManager(
monthly_wage=F('working_days') * F('daily_wage')
)
but because working_days is smallinteger and daily_wage is biginteger
this error raise:
Expression contains mixed types: SmallIntegerField, BigIntegerField.
You must set output_field.
How can I fix this

You set the output_field, with an ExpressionWrapper [Django-doc] for example:
from django.db.models import BigIntegerField, ExpressionWrapper
class DetailsList(models.Model):
# …
objects = AnnotationManager(
monthly_wage=ExpressionWrapper(
F('working_days') * F('daily_wage'),
output_field=BigIntegerField()
)
)

Related

Identify variables in Expression does not work

Given the following code based on Pyomo docs (https://pyomo.readthedocs.io/en/stable/developer_reference/expressions/managing.html#identifying-components-and-variables and https://pyomo.readthedocs.io/en/stable/pyomo_modeling_components/Expressions.html#expression-objects) I would expect to find a non-empty list, i.e. a list containing the variable model.x. Where is my misconception here?
import pyomo.environ as pyo
from pyomo.core.expr.current import identify_variables
model = pyo.ConcreteModel()
model.x = pyo.Var(initialize=1.0)
def _e(m,i):
return m.x*i
model.e = pyo.Expression([1,2,3], rule=_e)
assert len(list(identify_variables(model.e, include_fixed=True))) > 0
you need to convert the expression model.e into a list of expressions by using the values() method. Then, you can pass the list of expressions to the identify_variables function.
import pyomo.environ as pyo
from pyomo.core.expr.current import identify_variables
model = pyo.ConcreteModel()
model.x = pyo.Var(initialize=1.0)
def _e(m,i):
return m.x*i
model.e = pyo.Expression([1,2,3], rule=_e)
# Convert expression to list of expressions
expr_list = list(model.e.values())
# Pass list of expressions to identify_variables function
assert len(list(identify_variables(expr_list, include_fixed=True))) > 0
For reference, this is what I ended up with to have a non-empty list if any expression uses a Var:
from itertools import chain
import pyomo.environ as pyo
from pyomo.core.expr.current import identify_variables
model = pyo.ConcreteModel()
model.x = pyo.Var(initialize=1.0)
def _e(m,i):
return m.x*i
model.e = pyo.Expression([1,2,3], rule=_e)
assert len(list(chain(*(identify_variables(value) for value in list(component.values()))))) > 0

Nested Disjunctions in Abstract modelling of Pyomo

I am working on a small optimization model with some disjunctions. The way I did in a concrete model worked well:
from pyomo.environ import *
m = ConcreteModel()
m.d1 = Disjunct()
m.d2 = Disjunct()
m.d1.sub1 = Disjunct()
m.d1.sub2 = Disjunct()
m.d1.disj = Disjunction(expr=[m.d1.sub1, m.d1.sub2])
m.disj = Disjunction(expr=[m.d1, m.d2])
But now I tranfered the concrete model into an abstract formulation. I was able to fix everything instead of nesting the disjunctions. The way I did it was like:
#Disjunct 1
def _op_mode1(self, op_mode, t):
m = op_mode.model()
op_mode.c1 = po.Constraint(expr=m.x[t] == True)
#Disjunct 2
def _op_mode2(self, op_mode, t):
m = op_mode.model()
op_mode.c1 = po.Constraint(expr=m.x[t] == False)
#Disjunction 1
def _op_modes(self,m, t):
return [m.mode1[t], m.mode2[t]]
#Adding Components
self.model.del_component("mode1")
self.model.del_component("mode1_index")
self.model.add_component("mode1", pogdp.Disjunct(self.model.T, rule=self._op_mode1))
self.model.del_component("mode2")
self.model.del_component("mode2_index")
self.model.add_component("mode2", pogdp.Disjunct(self.model.T, rule=self._op_mode1))
self.model.del_component("modes")
self.model.del_component("modes_index")
self.model.add_component("modes", pogdp.Disjunction(self.model.T, rule=self._op_modes))`
As I previously mentioned, this works fine. But I haven`t found any way to nest the disjunctions. Pyomo alsways complains about the second layer of the disjuncts like "sub1".
Would anybody could give me a hint?
Many greetings
Joerg
The issue with the latest model above is that you are declaring m.d1 and m.d2 for each element of m.T, but they overwrite each other each time since they have the same name. You should be seeing warning messages logged for this. So if you uncomment your pprint of the model, you'll see that you only have the last ones you declared (with constraints on x[10]). So the first 9 Disjunctions in m.disjunction_ are disjunctions of Disjuncts that do not exist. The simplest fix for this is to give the disjuncts unique names when you declare them:
import pyomo.environ as pyo
import pyomo.gdp as pogdp
model = pyo.ConcreteModel()
model.T = pyo.RangeSet(0, 10)
model.x=pyo.Var(model.T,bounds=(-2, 10))
model.y=pyo.Var(model.T,bounds=(20, 30))
# This was also a duplicate declaration:
#model.disjunction_ = pogdp.Disjunction(model.T)
def d1(m, t):
disj = pogdp.Disjunct()
disj.c1= pyo.Constraint(expr=m.x[t] <= 10)
m.add_component('d1_%s' % t, disj)
return disj
def d2(m, t):
disj = pogdp.Disjunct()
disj.c1= pyo.Constraint(expr=m.x[t] >= 10)
m.add_component('d2_%s' % t, disj)
return disj
# sum x,y
def obj_rule(m):
return pyo.quicksum(pyo.quicksum([m.x[t] + m.y[t]], linear=False) for t in
m.T)
model.obj = pyo.Objective(rule=obj_rule)
def _op_mode_test(m, t):
disj1 = d1(m, t)
disj2 = d2(m, t)
return [disj1, disj2]
model.disjunction_ = pogdp.Disjunction(model.T, rule=_op_mode_test)
However, it would be cleaner (and probably easier down the line) to index the Disjuncts by m.T as well, since that's basically what the unique names are doing.
Block (and hence Disjunct rules) are passed the block (or disjunct) to be populated as the first argument. So, an "abstract" equivalent too your concrete model might look something like this:
model = AbstractModel()
#model.Disjunct()
def d1(d):
# populate the `d` disjunct (i.e., `model.d1`) here
pass
#model.Disjunct()
def d2(d):
#d.Disjunct()
def sub1(sd):
# populate the 'sub1' disjunct here
pass
#d.Disjunct()
def sub2(sd):
# populate the 'sub2' disjunct here
pass
d.disj = Disjunction(expr=[d.sub1, d.sub2])
model.disj = Disjunction(expr=[model.d1, model.d2])
There is a more fundamental question as to why you are converting your model over to "abstract" form. Pyomo Abstract models were mostly devised to be familiar to people coming from modeling in AMPL. While they will work with block-structured models, as AMPL was never really designed with blocks in mind, similarly block-oriented Abstract models tend to be unnecessarily cumbersome.
Here ist our new model:
import pyomo.environ as pyo
import pyomo.gdp as pogdp
model = pyo.ConcreteModel()
model.T = pyo.RangeSet(0,10)
model.x=pyo.Var(model.T,bounds=(-2, 10))
model.y=pyo.Var(model.T,bounds=(20, 30))
model.disjunction_=pogdp.Disjunction(model.T)
def d1(m,t):
m.d1 = pogdp.Disjunct()
m.d1.c1= pyo.Constraint(expr=m.x[t] <=10)
def d2(m,t):
m.d2 = pogdp.Disjunct()
m.d2.c1= pyo.Constraint(expr=m.x[t] >=10)
# sum x,y
def obj_rule(m):
return pyo.quicksum(pyo.quicksum([m.x[t] + m.y[t]], linear=False) for t in m.T)
model.obj = pyo.Objective(rule=obj_rule)
def _op_mode_test(m,t):
d1(m,t)
d2(m,t)
return [m.d1,m.d2]
model.disjunction_=pogdp.Disjunction(model.T,rule=_op_mode_test)
#model.pprint()
pyo.TransformationFactory('gdp.bigm').apply_to(model)
solver = pyo.SolverFactory('baron')
solver.solve(model)
print(pyo.value(model.obj))
I think it has something to do with the RangeSet. For a single step it works, but with more than one steps it throws an error: AttributeError: 'NoneType' object has no attribute 'component'
It would be great if you could have a look on it.
Many thanks
Here is the code which works pretty fine with bigm, but not with mbigm or hull transformation:
import pyomo.environ as pyo
import pyomo.gdp as pogdp
model = pyo.ConcreteModel()
model.T = pyo.RangeSet(2)
model.x=pyo.Var(model.T,bounds=(1, 10))
model.y=pyo.Var(model.T,bounds=(1, 100))
def _op_mode_sub(m, t):
m.disj1[t].sub1 = pogdp.Disjunct()
m.disj1[t].sub1.c1= pyo.Constraint(expr=m.y[t] == 60)
m.disj1[t].sub2 = pogdp.Disjunct()
m.disj1[t].sub2.c1= pyo.Constraint(expr=m.y[t] == 100)
return [m.disj1[t].sub1, m.disj1[t].sub2]
def _op_mode(m, t):
m.disj2[t].c1= pyo.Constraint(expr=m.y[t] >= 3)
m.disj2[t].c2= pyo.Constraint(expr=m.y[t] <= 5)
return [m.disj1[t], m.disj2[t]]
model.disj1 = pogdp.Disjunct(model.T)
model.disj2 = pogdp.Disjunct(model.T)
model.disjunction1sub = pogdp.Disjunction(model.T, rule=_op_mode_sub)
model.disjunction1 = pogdp.Disjunction(model.T, rule=_op_mode)
def obj_rule(m, t):
return pyo.quicksum(pyo.quicksum([m.x[t] + m.y[t]], linear=False) for t in m.T)
model.obj = pyo.Objective(rule=obj_rule)
model.pprint()
gdp_relax=pyo.TransformationFactory('gdp.bigm')
gdp_relax.apply_to(model)
solver = pyo.SolverFactory('glpk')
solver.solve(model)
print(pyo.value(model.obj))

How to disallow change of a Django field after creation?

I have a model like this:
THRESHOLD_CLASSES = {
MinimumThreshold.name: MinimumThreshold,
MaximumThreshold.name: MaximumThreshold
}
class Threshold(models.Model):
thingie = models.ForeignKey(Thingie, models.CASCADE)
threshold_types = THRESHOLD_CLASSES.keys()
type = models.TextField(choices=zip(threshold_types, threshold_types))
threshold = models.DecimalField()
With these related classes:
import abc
import operator
class Threshold(abc.ABC):
#abc.abstractmethod
def __init__(self):
pass
class MinimumThreshold(Threshold):
name = 'minimum'
operator = operator.lt
operator_name = 'lower than'
def __init__(self):
self.other_class = MaximumThreshold
class MaximumThreshold(Threshold):
name = 'maximum'
operator = operator.gt
operator_name = 'greater than'
def __init__(self):
self.other_class = MinimumThreshold
In my serializer I have to verify that the minimum threshold for a thingie is less than its maximum:
def validate(self, instance):
instance_type = instance['type']
instance_threshold_class = models.THRESHOLD_CLASSES[instance_type]
other_threshold_class = instance_threshold_class().other_class
other = models \
.AlarmParameterThreshold \
.objects \
.filter(thingie=instance['thingie'], type=other_threshold_class.name) \
.first()
if other:
if other_threshold_class.operator(instance['threshold'], other.threshold):
message = "The {} threshold cannot be {} the {} threshold of {}".format(
instance_type,
other_threshold_class.operator_name,
other_threshold_class.name,
other.threshold
)
raise serializers.ValidationError({'threshold': message})
This is already complicated, and I want to ensure that the complexity doesn't explode. One currently unhandled case if when the user changes the type of an existing Threshold - I would end up comparing it against an instance which is about to be replaced, and so I would have to make sure to exclude the instance which is currently being updated from the query to find the other threshold.
In this case, a simpler approach would be to simply disallow changes to type once it's been set, but I don't know of a way of doing that which is easier than excluding the current item from the comparison.
Please note that I'm not looking for a Django Forms solution - this is an API and the validation must be performed on the server side.

How to call a custom method with arguments in the models.py from views.py

I have this example:
class MyModel(models.Model):
# Some fields...
price = models.FloatField()
def calculate(self, number):
return self.price * number
In the views:
def whatever(request, any_number):
m = MyModel.objects.all()
c = m.calculate(any_number)
# More code...
It's a really easy example because I want to do something similar, so how can I do this?
Thank you!
You need to do it in a for loop, since m is an array of objects:
for item in m:
result = item.calculate(any_number)
# do some stuff with the result

Django ORM equivalent for this SQL..calculated field derived from related table

I have the following model structure below:
class Master(models.Model):
name = models.CharField(max_length=50)
mounting_height = models.DecimalField(max_digits=10,decimal_places=2)
class MLog(models.Model):
date = models.DateField(db_index=True)
time = models.TimeField(db_index=True)
sensor_reading = models.IntegerField()
m_master = models.ForeignKey(Master)
The goal is to produce a queryset that returns all the fields from MLog plus a calculated field (item_height) based on the related data in Master
using Django's raw sql:
querySet = MLog.objects.raw('''
SELECT a.id,
date,
time,
sensor_reading,
mounting_height,
(sensor_reading - mounting_height) as item_height
FROM db_mlog a JOIN db_master b
ON a.m_master_id = b.id
''')
How do I code this using Django's ORM?
I can think of two ways to go about this without relying on raw(). The first is pretty much the same as what #tylerl suggested. Something like this:
class Master(models.Model):
name = models.CharField(max_length=50)
mounting_height = models.DecimalField(max_digits=10,decimal_places=2)
class MLog(models.Model):
date = models.DateField(db_index=True)
time = models.TimeField(db_index=True)
sensor_reading = models.IntegerField()
m_master = models.ForeignKey(Master)
def _get_item_height(self):
return self.sensor_reading - self.m_master.mounting_height
item_height = property(_get_item_height)
In this case I am defining a custom (derived) property for MLog called item_height. This property is calculated as the difference of the sensor_reading of an instance and the mounting_height of its related master instance. More on property here.
You can then do something like this:
In [4]: q = MLog.objects.all()
In [5]: q[0]
Out[5]: <MLog: 2010-09-11 8>
In [6]: q[0].item_height
Out[6]: Decimal('-2.00')
The second way to do this is to use the extra() method and have the database do the calculation for you.
In [14]: q = MLog.objects.select_related().extra(select =
{'item_height': 'sensor_reading - mounting_height'})
In [16]: q[0]
Out[16]: <MLog: 2010-09-11 8>
In [17]: q[0].item_height
Out[17]: Decimal('-2.00')
You'll note the use of select_related(). Without this the Master table will not be joined with the query and you will get an error.
I always do the calculations in the app rather than in the DB.
class Thing(models.Model):
foo = models.IntegerField()
bar = models.IntegerField()
#Property
def diff():
def fget(self):
return self.foo - self.bar
def fset(self,value):
self.bar = self.foo - value
Then you can manipulate it just as you would any other field, and it does whatever you defined with the underlying data. For example:
obj = Thing.objects.all()[0]
print(obj.diff) # prints .foo - .bar
obj.diff = 4 # sets .bar to .foo - 4
Property, by the way, is just a standard property decorator, in this case coded as follows (I don't remember where it came from):
def Property(function):
keys = 'fget', 'fset', 'fdel'
func_locals = {'doc':function.__doc__}
def probeFunc(frame, event, arg):
if event == 'return':
locals = frame.f_locals
func_locals.update(dict((k,locals.get(k)) for k in keys))
sys.settrace(None)
return probeFunc
sys.settrace(probeFunc)
function()
return property(**func_locals)