Factory boy field not getting expected value - python

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).

Related

How to get integer ID of Django Factory Boy object?

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]"

Django: split one model instance into two

I have a Django model Adventure with two datetime fields:
from django.db import models
class Adventure(models.Model):
start_time = models.DateTimeField()
end_time = models.DateTimeField()
(...)
There's an instance of Adventure, let's say:
Adventure(start_time=TIME_1, end_time=TIME_2, ...)
Assuming there is some TIME_X between TIME_1 and TIME_2 (TIME_1 < TIME_X < TIME_2), how can I split one Adventure object into two separate objects, so after splitting I would have:
#first instance
Adventure(start_time=TIME_1, end_time=TIME_X, ...)
#second instance
Adventure(start_time=TIME_X, end_time=TIME_2, ...)
Adventure has more fields, which should be the same for both instances (except for PK, of course).
You could simply use orm methods to change one existing object and create only one new object:
# Get the first instance
adventure = Adventure.objects.get(start_time=TIME_1, end_time=TIME_2, ...)
middle_time = TIME_X
# save old end_time
old_end_time = adventure.end_time
# Modify first instance and save to DB
adventure.end_time = middle_time
adventure.save()
# Create new instance
adventure.pk = None
adventure.start_time = middle_time
adventure.end_time = old_end_time
adventure.save() # This will create a new object
As a result you will have two database entries with your other attributes the same except for the two start_time and end_time attributes.
You can do it with a method:
import copy
original_adventure = Adventure(start_time=TIME_1, end_time=TIME_2, ...)
adventure_split_1, adventure_split_2 = split_adventure(original_adventure, TIME_MIDDLE)
def split_adventure(adventure, middle_time):
adventure_split_1 = copy.deepcopy(adventure)
adventure_split_1.end_time = middle_time
adventure_split_2 = copy.deepcopy(adventure)
adventure_split_2.start_time = middle_time
return (adventure_split_1, adventure_split_2)

count the sales of a worker

I am trying to count the sales made by a worker but I get the following error when using the code mentioned below:
TypeError: object of type 'bool' has no len()
class Movement_type (models.Model):
_name = 'project_rc.movement_type'
_rec_name = 'movement_type'
type_movement = fields.Selection ([('purchase', 'Purchase'), ('sale', 'Sale'), ('merma', 'Merma')], string = "Movement type", required = True)
class Worker (models.Model):
_name = 'project_rc.worker'
_rec_name = 'name'
sales_counter = fields.Integer (string = "Sales made", compute = "get_sales_realized", store = True)
#api.depends('move_type_ids')
def get_sales_realized (self):
for rec in self:
rec.count_sale = len (rec.move_type_ids.mov_type == 'sale')
I'm not familiar with whatever framework you are using, but if you look at the error you are getting you can see that it is correct.
On line 3, you write rec.move_type_ids.mov_type == 'sale'. It doesn't matter what rec.move_type_ids.mov_type is, when you compare it to something with ==, the answer will either be True or False. It doesn't make sense to take the length of a boolean (t/f).
From the context, I'm guessing that rec.move_type_ids is a list of objects and you want to figure out how many of them have a mov_type property equal to 'sale'. If that's the case, then you could easily do that with a for loop:
sales = []
for thing in rec.move_type_ids:
if thing.type == 'sale':
sales.append(thing)
rec.count_sale = len(sales)
If you want to get a little fancier, you can do that with a filter function:
rec.count_sale = len(filter(lambda x: x.mov_type == 'sale', rec.move_type_ids))

Calculate a value from GraphQL and save it in Django models

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.

Python: How to determine the type of a property in a class?

I have the following classes defined that inherits from some other classes. Goblin is a Python dependency package that I am extending from.
class AnnotatedVertexProperty(goblin.VertexProperty):
notes = goblin.Property(goblin.String)
datetime = goblin.Property(DateTime)
class KeyProperty(goblin.Property):
def __init__(self, data_type, *, db_name=None, default=None, db_name_factory=None):
super().__init__(data_type, default=None, db_name=None, db_name_factory=None)
class TypedVertex(goblin.Vertex):
def __init__(self):
self.vertex_type = self.__class__.__name__.lower()
super().__init__()
class TypedEdge(goblin.Edge):
def __init__(self):
self.edge_type = self.__class__.__name__.lower()
super().__init__()
class Airport(TypedVertex):
#label
type = goblin.Property(goblin.String)
airport_code = KeyProperty(goblin.String)
airport_city = KeyProperty(goblin.String)
airport_name = goblin.Property(goblin.String)
airport_region = goblin.Property(goblin.String)
airport_runways = goblin.Property(goblin.Integer)
airport_longest_runway = goblin.Property(goblin.Integer)
airport_elev = goblin.Property(goblin.Integer)
airport_country = goblin.Property(goblin.String)
airport_lat = goblin.Property(goblin.Float)
airport_long = goblin.Property(goblin.Float)
At run time, I need to iterate thrown each one of the properties and be able to determine its class type (keyProperty or goblin.Property) I also need to be able to determine if the value is a string, integer, etc...
During instantiation, I create an airport object and set the values as following:
lhr = Airport()
lhr.airport_code = 'LHR'
print (lhr.airport_code.__class__.mro())
lhr.airport_city = 'London'
lhr.airport_name = 'London Heathrow International Airport'
lhr.airport_region = 'UK-EN'
lhr.airport_runways = 3
lhr.airport_longest_runway = 12395
lhr.airport_elev = 1026
lhr.airport_country = 'UK'
lhr.airport_lat = 33.6366996765137
lhr.airport_long = -84.4281005859375
However when I inspect the object while debugging it, all I get is the property name, defined as string and values, defined as string, integer, etc... How can I check for the object type for each property?
Any help or suggestions on how to handle this ?
I figured out what I was looking for. I had to call element.class.dict.items(): and I can get a dictionary with all the properties, mappings, etc...

Categories

Resources