I am trying to calculate a value from GraphQL. I am sending mutation to Django models but before save it I want to calculate this value with if statement (if the value is greater than 10 divide by 2, if is less than 10 multiply by 2).
I don't know where to add this function.
Here is my mutation in schema.py
class CreatePrice(graphene.Mutation):
price = graphene.Field(PriceType)
class Arguments:
price_data = PriceInput(required=True)
#staticmethod
def mutate(root, info, price_data):
price = Price.objects.create(**price_data)
return CreatePrice(price=price)
class Mutation(graphene.ObjectType):
create_product = CreateProduct.Field()
create_price = CreatePrice.Field()
schema = graphene.Schema(query = Query, mutation=Mutation)
And here is my Django model. Base price is calculated value and function name has two options(*2 or /2 it depends of initial value).
class Price(models.Model):
base_price = models.CharField(max_length = 20)
function_name = models.CharField(max_length = 20, choices = PROMO_FUNCTION)
def __str__(self):
return self.price_name
P.S. Sorry for bad English. Thanks!
I don't know why you are using CharField for base_price. So, I suggest you to do this:
#staticmethod
def mutate(root, info, price_data):
if int(price_data.base_price) >= 10:
price_data.base_price = str(int(price_data.base_price) / 2)
else:
price_data.base_price = str(int(price_data.base_price) * 2)
price = Price(base_price=price_data.base_price, function_name=price_data.function_name)
price.save()
return CreatePrice(price=price)
You can also create records in database by creating object and using save method on it.
Related
I have a factory boy factory that uses Django that I need to access the ID of the generated objects. However, whenever I attempt to get that ID, I receive TypeErrors. Any idea what I am missing?
# factories.py
class PartNoFactory(factory.django.DjangoModelFactory):
class Meta:
model = PartNo
id = factory.fuzzy.FuzzyInteger(1, 1000000, step=1)
# have also tried id = factory.Sequence(lambda n: n + 1)
# have also tried id = int(factory.Sequence(lambda n: n + 1)), which results in error "type Sequence cannot be assigned to paramater "_x"
# test_factories.py
def mock_child_part_nos(arg_1: PartNo) -> 'list[int]':
mock_part_no_one = PartNoFactory()
mock_part_no_two = PartNoFactory()
mock_part_no_three = PartNoFactory()
return [mock_part_no_one.id, mock_part_no_two.id, mock_part_no_three.id]
# if using FuzzyInteger: "Expression of type "list[FuzzyInteger]" cannot be assigned to return type "list[int]"
# if using Sequence: "Expression of type "list[Sequence]" cannot be assigned to return type "list[int]"
I have a fairly complex hybrid_property. This is a vendor model, which has multiple skuchannels (products). What it does is: Based on the target_stock_duration (e.g. we want to keep items in stock for 4 months) calculate how many units have to be ordered and how much this would cost. This gives us the potential.
class Vendor(db.Model):
__tablename__ = "vendor"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(150))
b2c_price_factor = db.Column(db.Float, nullable=False)
skuchannels = db.relationship("SKUChannel", back_populates="vendor")
#hybrid_property
def po_potential(self):
"""This is a "virtual" property that will that can be used in the admin view. It calculates
the potential value for a comming PO.
Returns:
_type_: _description_
"""
potential = 0
for item in self.skuchannels:
purchasing_price = item.purchasing_price if item.purchasing_price != None else 0
target_stock_duration = 4
try:
to_order = item.average_monthly_sales * target_stock_duration - item.stock_level #calculate how many units we have to order
if to_order < 0:
to_order = 0
except TypeError:
to_order = 0
potential = potential + purchasing_price * to_order #calculate how much everything costs
return potential
well this hybrid_property works just fine, but I would very much like to sort this property. with #po_potential.expression -> well I have no clue how to do this, because in my understanding it should return a select object. Is there any other way?
This should get you started:
class Vendor(Base):
...
...
#po_potential.expression
def po_potential(cls):
target_stock_duration = 4
return (
select(func.sum(
func.ISNULL(SKUChannel.purchasing_price, 0) *
func.GREATEST(0, SKUChannel.average_monthly_sales * target_stock_duration - SKUChannel.stock_level, 0)
))
.where(SKUChannel.vendor_id == cls.id)
.label('po_potential')
)
I am using factory boy to generate data for my django application.
It is a tennis matches app which has player one and two as shown in below class. Either of it will be a winner which will be store in winner_one field.
I am getting some third player name in this field instead of player one or two. That player is also present in table.
Please advise what would be the best way to fix this?
class MatchFactory(factory.django.DjangoModelFactory):
class Meta:
model = Match
player_one = factory.SubFactory(UserFactory)
player_two = factory.SubFactory(UserFactory)
league = factory.Iterator(League.objects.all())
type = fuzzy.FuzzyChoice(Match.MATCH_CHOICES, getter=lambda c: c[0])
winner_one = random.choice([player_one, player_two])
start_date = fuzzy.FuzzyNaiveDateTime(
datetime.today() + relativedelta(months=1),
datetime.today() + relativedelta(months=3)
)
end_date = start_date
This one seems like a good use case of factory_boy's post generation hook.
class MatchFactory(factory.django.DjangoModelFactory):
class Meta:
model = Match
player_one = factory.SubFactory(UserFactory)
player_two = factory.SubFactory(UserFactory)
league = factory.Iterator(League.objects.all())
type = fuzzy.FuzzyChoice(Match.MATCH_CHOICES, getter=lambda c: c[0])
start_date = fuzzy.FuzzyNaiveDateTime(
datetime.today() + relativedelta(months=1),
datetime.today() + relativedelta(months=3)
)
end_date = start_date
#factory.post_generation
def winner_one(self, create, extracted, **kwargs):
if extracted:
self.winner_one = extracted
else:
self.winner_one = random.choice([self.player_one, self.player_two])
The issue stems from the random.choice([user_one, user_two]) declaration: that declaration is executed at module import time, not when running the factory.
At that point, both values are factory.SubFactory(UserFactory) — i.e a recipe for creating a new user.
Once random.choice() is called, it will return one of the declarations; your code is thus equivalent to:
class MatchFactory(factory.django.DjangoModelFactory):
...
player_one = factory.SubFactory(UserFactory)
player_two = factory.SubFactory(UserFactory)
winner_one = factory.SubFactory(UserFactory)
It picks 3 different users each time.
I would suggest going for the following pattern:
Add a "parameter" to decide which player should win;
Use that value to choose the right attribute:
class MatchFactory(factory.django.DjangoModelFactory):
class Meta:
model = Match
class Params:
# Decide who the winner is; that field won't be passed to the `Match` model.
winner = factory.fuzzy.FuzzyChoice([1, 2])
player_one = factory.SubFactory(UserFactory)
player_two = factory.SubFactory(UserFactory)
winner_one = factory.LazyAttribute(
lambda o: o.player_one if o.winner == 1 else o.player_two
)
With that pattern, you can also "choose" the winner when calling the factory:
MatchFactory(player_one=some_player, player_two=some_player, winner=1).
NOTE:
This is a detailed question asking how best to implement and manage Database caching in my web-application with memcached. This question uses Python/Django to illustrate the data-models and usage, but the language is not really that relevant. I'm really more interested in learning what the best strategy to maintain cache-coherency is. Python/Django just happens to be the language I'm using to illustrate this question.
RULES OF MY APPLICATION:
I have a 3 x 3 grid of cells of integers
The size of this grid may increase or decrease in the future. Our solution must scale.
Their is a cumulative score for each row that is calculated by summing (value * Y-Coord) for each cell in that row.
Their is a cumulative score for each column that is calculated by summing (value * X-Coord) for each cell in that column.
The values in the cells change infrequently. But those values and the scores scores are read frequently.
I want to use memcached to minimize my database accesses.
I want to minimize/eliminate storing duplicate or derived information in my database
The image below shows an example of the state of the my grid.
MY CODE:
import memcache
mc = memcache.Client(['127.0.0.1:11211'], debug=0)
class Cell(models.Model):
x = models.IntegerField(editable=False)
y = models.IntegerField(editable=False)
# Whenever this value is updated, the keys for the row and column need to be
# invalidated. But not sure exactly how I should manage that.
value = models.IntegerField()
class Row(models.Model):
y = models.IntegerField()
#property
def cummulative_score(self):
# I need to do some memcaching here.
# But not sure the smartest way to do it.
return sum(map(lambda p: p.x * p.value, Cell.objects.filter(y=self.y)))
class Column(models.Model):
x = models.IntegerField()
#property
def cummulative_score(self):
# I need to do some memcaching here.
# But not sure the smartest way to do it.
return sum(map(lambda p: p.y * p.value, Cell.objects.filter(x=self.x)))
SO HERE IS MY QUESTION:
You can see that I have setup a memcached instance. Of course I know how to insert/delete/update keys and values in memcached. But given my code above how should I name the keys appropriately? It won't work if the key names are fixed since there must exist individual keys for each row and column. And critically how can I ensure that the appropriate keys (and only the appropriate keys) are invalidated when the values in the cells are updated?
How do I manage the cache invalidations whenever anyone updates Cell.values so that the database accesses are minimized? Isn't there some django middleware that can handle this book-keeping for me? The documents that I have seen don't do that.
# your client, be it memcache or redis, assign to client variable
# I think both of them use set without TTL for permanent values.
class Cell(models.Model):
x = models.IntegerField(editable=False)
y = models.IntegerField(editable=False)
value = models.IntegerField()
def save(self, *args, **kwargs):
Cell.cache("row",self.y)
Cell.cache("column",self.x)
super(Cell, self).save(*args, **kwargs)
#staticmethod
def score(dimension, number):
return client.get(dimension+str(number), False) or Cell.cache(number)
#staticmethod
def cache(dimension, number):
if dimension == "row":
val = sum([c.y * c.value for c in Cell.objects.filter(y=number)])
client.set(dimension+str(self.y),val)
return val
if dimension == "column":
val = sum([c.x * c.value for c in Cell.objects.filter(x=number)])
client.set(dimension+str(self.x),val)
return val
raise Exception("No such dimension:"+str(dimension))
If you want to cache individual row/column combinations you should append the object id to the key name.
given a x, y variables:
key = 'x={}_y={}'.format(x, y)
I would use the table name and just append the id, row id could just be the table PK, column id could just be the column name, like this
key = '{}_{}_{}'.format(table_name, obj.id, column_name)
In any case I suggest considering caching the whole row instead of individuals cells
The Cell object can invalidate cached values for its Row and Column when the model object is saved.
(Row and Column are plain objects here, not Django models, but of course you can change that if you need to store them in the database for some reason.)
import memcache
mc = memcache.Client(['127.0.0.1:11211'], debug=0)
class Cell(models.Model):
x = models.IntegerField(editable=False)
y = models.IntegerField(editable=False)
# Whenever this value is updated, the keys for the row and column need to be
# invalidated. But not sure exactly how I should manage that.
value = models.IntegerField()
def invalidate_cache(self):
Row(self.y).invalidate_cache()
Column(self.x).invalidate_cache()
def save(self, *args, **kwargs):
super(Cell, self).save(*args, **kwargs)
self.invalidate_cache()
class Row(object):
def __init__(self, y):
self.y = y
#property
def cache_key(self):
return "row_{}".format(self.y)
#property
def cumulative_score(self):
score = mc.get(self.cache_key)
if not score:
score = sum(map(lambda p: p.x * p.value, Cell.objects.filter(y=self.y)))
mc.set(self.cache_key, score)
return score
def invalidate_cache(self):
mc.delete(self.cache_key)
class Column(object):
def __init__(self, x):
self.x = x
#property
def cache_key(self):
return "column_{}".format(self.x)
#property
def cumulative_score(self):
score = mc.get(self.cache_key)
if not score:
score = sum(map(lambda p: p.y * p.value, Cell.objects.filter(x=self.x)))
mc.set(self.cache_key, score)
return score
def invalidate_cache(self):
mc.delete(self.cache_key)
So I am able to generate a random id using uuid
So far so good
But when I try to database i get same value
def f():
d = uuid4()
str = d.hex
return str[0:16]
class Q(models.Model):
a = models.CharField(max_length=150)
b = models.IntegerField(max_length=25)
c = models.IntegerField(max_length=32 , default=0)
d = models.ManyToManyField(Ans , related_name='aa')
e = models.CharField(max_length=18 , default = f() ,unique=True )
class Ans(models.Model):
sub = models.CharField(max_length=150)
-----------------------------------------------------------------
And I'm inserting like this
def ins(request):
t =random.randint(0, 1000)
p = Q(a = t , b=0 , c=0)
p.save()
return HttpResponse('Saved')
Just curious what the hell is happening here
Side note: If I set e.unique = False I get 2-3 with the same e values before I get a new
UUID values
You should not call the function that you are passing to default:
e = models.CharField(max_length=18, default=f, unique=True)
FYI, according to docs, you should pass a value or a callable:
The default value for the field. This can be a value or a callable
object. If callable it will be called every time a new object is
created.