Add a CALCULATED fields with if-else condition in Django model - django-models

How can i add a calculated field with if-else condition in Django model?
for instance,
def _get_total(self):
"Returns the Overall Backlog"
return self.Forecast - self.Actual_t
Overall_Backlog = property(_get_total)
here, i want to create Overall_Backlog with a condition like if (self.Forecast - self.Actual_t)<0 then 0 else (self.Forecast - self.Actual_t).
Please help!

Exactly like that:
#property
def Overall_Backlog(self):
"Returns the Overall Backlog"
val = self.Forecast - self.Actual_t
if val < 0:
return 0
return val
A disadvantage of using a property is however that the database does not know anything about properties and methods, and thus can not filter. An alternative to using properties is using .annotate(…) [Django-doc]:
from django.db.models import Value
from django.db.models.functions import Greatest
MyModel.objects.annotate(
overall_backlog=Greatest(F('Forecast') - F('Actual_t'), Value(0))
)
The MyModel objects that arise from this QuerySet will have an extra attribute .overall_backlog that is the maximum of Forecast - Actual_t and 0.

Related

Return object after performing intersection of two arrays based on attribute

I have two arrays, both filled with objects that have numerous attributes. Both arrays are holding the same object types. I want to find where objects match based on their attribute id
Object example:
#<Link:0x00007fac5eb6afc8 #id = 2002001, #length=40, #area='mars' ...>
Example arrays filled with objects:
array_links = [<Link:0x00007fac5eb6afc8>, <Link:0x00007fdf5eb7afc2>, <Link:0x000081dag6zb7agg8>... ]
selected_links = [<Link:0x00007fad8ob6gbh5>, <Link:0x00007fdg7hh4tif4>, <Link:0x000081dag7ij5bhh9>... ]
If these were strings of the object IDs and there was a match, I could use:
intersection = array_links & selected_links
However I want to do this based on their attribute and return a matching object itself.
Something like:
intersection = array_links.select(&:id) & selected_links.select(&:id)
But of course, not that, as that doesn't work, any ideas? :)
you can:
1 :
override the eql?(other) method then the array intersection will work
class Link < ApplicationRecord
def eql?(other)
self.class == other.class && self.id == other&.id # classes comparing class is a guard here
end
# you should always update the hash if you are overriding the eql?() https://stackoverflow.com/a/54961965/5872935
def hash
self.id.hash
end
end
2:
use array.select:
array_links.flat_map {|i| selected_links.select {|k| k.user_id == i.user_id }}
If they are the same object in memory, ie array_links = [<Link:0x123] and selected_links = [<Link:0x123>], then your solution of:
intersection = array_links & selected_links
Should work.
If they are not, you could loop over you array_links and select those which are in selected_links:
intersection = array_links.select do |link|
link.id.in? selected_links.map(&:id)
end
The result will be the same if you loop over selected_links and select those in array_links.
Depending on your resources and the size of these arrays, you could memoize selected_links.map(&:id) to prevent this from being re-built on each iteration.

Validating array insertion in Rails

I have Table1 with attribute attribute1, which is an array of integer. My controller allows for one insertion at a time. So, in the controller:
def add_attribute1_item
table1 = Table1.find(params[:id])
table1.attribute1 << add_params[:attribute1_item]
table1.save!
render json: table1
rescue
render_errors_for(table1)
end
I want to validate this attribute1_item value, ignoring the old values that have been stored in attribute1 array, e.g. if table1.attribute1 contains 99 and I call the controller add_attribute1_item to add 100, I only want to check whether 100 is valid or not, ignoring 99.
class Task < ApplicationRecord
.
.
.
validate :attribute1_item_is_valid, if: -> { attribute1.present? }
.
.
.
def attribute1_item_is_valid
# validate the item by accessing attribute1
end
I am unsure with this approach because when I access attribute1 in attribute1_item_is_valid, it is the whole array instead of the new item. Is this approach good enough by calling attribute1.last() or is there a more correct method?
thank you
Instead of trying to validate this in the model, validate the form entry.
Create a model for the form and use normal validations.
class SomeForm
include ActiveModel::Model
attr_accessor :id, :attribute1_item
validate :id, presence: true, numericality: { only_integer: true }
validate :attribute1_item, presence: true
end
def add_attribute1_item
form = SomeForm.new(params)
if form.invalid?
# render form.errors
return
end
table1 = Table1.find(form.id)
table1.attribute1 << form.attribute1_item
table1.save!
render json: table1
rescue
render_errors_for(table1)
end

How to create a completely (uniformly) random dataset on PyTorch

I need to run some experiments on custom datasets using pytorch. The question is, how can I create a dataset using torch.Dataloader?
I have two lists, one is called Values and has a datapoint tensor at every entry, and the other one is called Labels, that has the corresponding label. What I did is the following:
for i in range(samples):
dataset[i] = [values[i],labels[I]]
So I have a list with datapoint and respective label, and then tried the following:
dataset = torch.tensor(dataset).float()
dataset = torch.utils.data.TensorDataset(dataset)
data_loader = torch.utils.data.DataLoader(dataset=dataset, batch_size=100, shuffle=True, num_workers=4, pin_memory=True)
But, first of all, I get the error "Not a sequence" in the torch.tensor command, and second, I'm not sure this is the right way of creating one. Any suggestion?
Thank you very much!
You do not need to overload DataLoader, but rather create a Dataset for your data.
For instance,
class MyDataset(Dataset):
def __init__(self):
super(MyDataset, self).__init__()
# do stuff here?
self.values = values
self.labels = labels
def __len__(self):
return len(self.values) # number of samples in the dataset
def __getitem__(self, index):
return self.values[index], self.labels[index]
Just to enrich the answer by #shai
class MyDataset(Dataset):
def __init__(self, values):
super(MyDataset, self).__init__()
self.values = values
def __len__(self):
return len(self.values)
def __getitem__(self, index):
return self.values[index]
values = np.random.rand(51000, 3)
dataset = MyDataset(values)

Is there any way to specify how to compare of array of objects for .difference function in Ruby 2.6.0?

I am trying to compare an array of externally defined Objects. I was hoping I would be able to do a simple .difference, a function that was introduced in Ruby 2.6.0 but after looking at it: https://ruby-doc.org/core-2.6/Array.html#method-i-difference I'm not sure I can specify a custom comparison.
Okay assuming we have a simple Object Num
# Pretend we don't have access to this, just for reference
class Num
def initialize(val)
#val = val
end
def val
#val
end
end
And I have two arrays, one is a subset of the other. I want to find what the subset is missing. In this following example I want the difference to be the Object with value 3, since it doesn't exist in the subset.
all = [Num.new(1), Num.new(2), Num.new(3)]
subset = [Num.new(1), Num.new(2)]
The default .difference function compares using .eql? between the two objects so the difference does not give the expected result:
all.difference(subset)
=> [#<Num:0x00007fcae19e9540 #val=1>, #<Num:0x00007fcae19e9518 #val=2>, #<Num:0x00007fcae19e94f0 #val=3>]
I was able to create my own custom hacky solution to properly give me the values I want:
def custom_difference(all, subset)
diff = all.reject { |all_curr|
subset.find{ |subset_curr|
subset_curr.val == all_curr.val
} != nil
}
end
custom_difference(all, subset)
=> [#<Num:0x00007fcae19e94f0 #val=3>]
But I want to know if there's anyway to utilize the existing .difference function, I was trying to use like this as well in order to override the way the two objects are compared:
all.difference(subset) { |a, b|
a.val <=> b.val
}
=> [#<Num:0x00007fcae19e9540 #val=1>, #<Num:0x00007fcae19e9518 #val=2>, #<Num:0x00007fcae19e94f0 #val=3>]
But this doesn't do anything to adjust the way the comparison occurs (AFAIK) Am I doing something wrong? Is this just not possible? :'(
If you don't want to add eql? to the class as described by Aleksei Matiushkin (e.g. if you want to use multiple criteria for different things), there's no way to reuse #difference. Doing what you were doing is pretty much what you need to do, though with Array#include? is O(N^2), so I like sticking Set in there:
Set.new(subset.map(&:val)).then { |s| all.reject { |x| s === x.val } }
# => [#<Num:0x00007febd32330e0 #val=3>]
or, as a new method:
module ArrayWithDifferenceBy
refine Array do
def difference_by(other)
other_set = Set.new(other.map { |x| yield x })
self.reject { |x| other_set.include?(yield x) }
end
end
end
module TestThis
using ArrayWithDifferenceBy
all = [Num.new(1), Num.new(2), Num.new(3)]
subset = [Num.new(1), Num.new(2)]
all.difference_by(subset, &:val)
end
# => [#<Num:0x00007febd32330e0 #val=3>]
You want to simply override #eql? on your object.
class Num
def initialize(val)
#val = val
end
def val
#val
end
def eql?(comp)
#val == comp.val
end
end
Now if you try:
all = [Num.new(1), Num.new(2), Num.new(3)]
subset = [Num.new(1), Num.new(2)]
all.difference(subset) => [#<Num:0x00007fa7f7171e60 #val=3>]

Case-insensitive exact match with SQLAlchemy

How can I ensure that the = operator is always rendered case-insensitive? Are comparisions with the LOWER or the UPPER functions the best bet for performance? ILIKE seems to be very slow.
If you need only case-insensitivity use upper or lower since like is not only about case-insensitivity
example of lower:
my_string = 'BarFoo'
session.query(Foo).filter(func.lower(Foo.bar) == my_string.lower()).all()
see some more info on like here how to execute LIKE query in sqlalchemy?
For case-insensitive comparisons, you can subclass Comparator.
Building Custom Comparators
The example class below allows case-insensitive comparisons on the attribute named word_insensitive:
from sqlalchemy.ext.hybrid import Comparator, hybrid_property
from sqlalchemy import func, Column, Integer, String
from sqlalchemy.orm import Session
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class CaseInsensitiveComparator(Comparator):
def __eq__(self, other):
return func.lower(self.__clause_element__()) == func.lower(other)
class SearchWord(Base):
__tablename__ = 'searchword'
id = Column(Integer, primary_key=True)
word = Column(String(255), nullable=False)
#hybrid_property
def word_insensitive(self):
return self.word.lower()
#word_insensitive.comparator
def word_insensitive(cls):
return CaseInsensitiveComparator(cls.word)
Above, SQL expressions against word_insensitive will apply the LOWER() SQL function to both sides:
>>> print Session().query(SearchWord).filter_by(word_insensitive="Trucks")
SELECT searchword.id AS searchword_id, searchword.word AS searchword_word FROM searchword
WHERE lower(searchword.word) = lower(:lower_1)
The CaseInsensitiveComparator above implements part of the ColumnOperators interface. A “coercion” operation like lowercasing can be applied to all comparison operations (i.e. eq, lt, gt, etc.) using Operators.operate():
class CaseInsensitiveComparator(Comparator):
def operate(self, op, other):
return op(func.lower(self.__clause_element__()), func.lower(other))

Resources