class Purchase(Model): """ Custom data model derived from Django's generic `Model` class. This class defines a purchase made by a certain customer (buyer) for a certain fruit. Hence it stores a reference to a buyer via a `ForeignKey` to `Player` and a reference to a fruit offer via a `ForeignKey` to `FruitOffer`. Additionally, the amount of fruit bought is stored. """ amount = models.IntegerField(min=1) # fruits taken # price = models.CurrencyField(min=0) optional: allow bargaining fruit = ForeignKey(FruitOffer, on_delete=models.CASCADE ) # creates many-to-one relation -> this purchase # relates to a certain fruit offer # many purchases can be made for this offer (as long # as there's at least 1 fruit left) buyer = ForeignKey( Player, on_delete=models.CASCADE ) # creates many-to-one relation -> this fruit is bought # by a certain player *in a certain round*. a player # can buy many fruits. class CustomModelConf: """ Configuration for otreeutils admin extensions. This class and its attributes must be existent in order to include this model in the data viewer / data export. """ data_view = {'exclude_fields': ['buyer_id'], 'link_with': 'buyer'} export_data = {'exclude_fields': ['buyer_id'], 'link_with': 'buyer'}
class Commentaire(Model): player = ForeignKey( Player, blank=True, null=True ) # creates 0:m relation -> this comment was made by a certain player, or by an expert parent_comment = ForeignKey( 'self', blank=True, null=True, related_name='children' ) # creates 0:m relation -> this comment is related to a parent comment or not argument = ForeignKey( Argument, blank=True, null=True ) # creates 0:m relation -> this comment is related to an argument or not
class PriceDim(Model ): # our custom model inherits from Django's base class "Model" value = models.IntegerField() dimnum = models.IntegerField() # in reality, there will be either, but not both, an ask or a bid associated with each pricedim ask = ForeignKey( Ask, blank=True, null=True ) # creates 1:m relation -> this decision was made by a certain seller bid = ForeignKey(Bid, blank=True, null=True)
class QuestionToExpert(Model): question_text = models.TextField() related_question = models.CharField(choices=Choices.questions, initial=Choices.questions[0]) player = ForeignKey( Player ) # creates 1:m relation -> this question was asked by a certain player
class Trial(Model): """ Trial model holds all information for a single trial made by a player. This is a "custom data model" in a 1:n relationship between Player and Trial. It uses an otreeutils "CustomModelConf" for monitoring and exporting the collected data from this model. """ block = models.IntegerField() # block number (-> round number) trial = models.IntegerField() # trial number in that round for that participant stimulus = models.StringField() # shown word or name stimulus_class = models.StringField() # words or names stimulus_level = models.StringField() # pos/neg or tr/dt response_key = models.StringField() # response: key that was pressed by participant response_correct = models.BooleanField() # records whether response was correct response_time_ms = models.IntegerField() # time it took until key was pressed since word/name was shown player = ForeignKey(Player) # make a 1:n relationship between Player and Trial class CustomModelConf: """ Configuration for otreeutils admin extensions. """ data_view = { # define this attribute if you want to include this model in the live data view 'exclude_fields': ['player'], 'link_with': 'player' } export_data = { # define this attribute if you want to include this model in the data export 'exclude_fields': ['player_id'], 'link_with': 'player' }
class Ask(Model): """ Stores details of a seller's ask """ total = models.IntegerField(min=Constants.minprice, max=Constants.maxprice, doc="Total price across all dims") stdev = models.FloatField(min=0, doc="Standard deviation of price dimensions") auto = models.BooleanField( doc="True if ask was generated automatically by the 'distribute' button" ) manual = models.BooleanField( doc= "True if ask was generated by seller manually adjusting a single price dim" ) player = ForeignKey(Player) # def generate_pricedims(self): # """ set through auto-generation of price dims """ # for i in range(self.player.subsession.dims): # # # pd = PriceDim(ask=self, dimnum=i + 1) # pd = self.pricedim_set.create(dimnum=i + 1) # pd.save() def set_pricedims(self, pricedims): """ set through manual manipulation of fields """ for i in range(self.player.subsession.dims): pd = self.pricedim_set.create(dimnum=i + 1, value=pricedims[i]) pd.save()
class ProdDim(Model): #based off pricedim class value = models.IntegerField(doc="The value of this product dim") dimnum = models.IntegerField( doc="The number of the dimension of this price dim") product = ForeignKey(Product, blank=True, null=True)
class Bid(Model): # inherits from Django's base "Model" BID_CHOICES = currency_range(c(Constants.reserve_price), c(Constants.maximum_bid), c(Constants.bid_price_increment)) round = models.PositiveIntegerField() bid = models.CurrencyField(choices=BID_CHOICES) accepted = models.PositiveIntegerField() pid_in_group = models.PositiveIntegerField() subsession_id = models.PositiveIntegerField() player = ForeignKey(Player) # creates 1:m relation -> this bid was made by a certain player
class ExternalFeedRecord(Model, CSVRowMixIn): submitted_file = ForeignKey(ExogenousEventFile, on_delete=models.CASCADE) arrival_time = models.FloatField() market_id_in_subsession = models.StringField() e_best_bid = models.IntegerField() e_best_offer = models.IntegerField() e_signed_volume = models.FloatField()
class ExogenousOrderRecord(Model, CSVRowMixIn): submitted_file = ForeignKey(ExogenousEventFile, on_delete=models.CASCADE) arrival_time = models.FloatField() market_id_in_subsession = models.StringField() price = models.IntegerField() time_in_force = models.IntegerField() buy_sell_indicator = models.StringField()
class MovieSelection(Model): group = ForeignKey(Group) key = models.StringField() name = models.StringField() description = models.StringField() isRemaining = models.BooleanField() isChecked = models.BooleanField(initial=False, widget=CheckboxInput) embeddedVideo = models.StringField()
class Orderapi(Model): idx = models.IntegerField() # will be randomly generated region = models.StringField(initial='Region X') bid = models.PositiveIntegerField(min=0, max=1000, initial=0) bidvol = models.IntegerField(min=0, max=3, initial=0) offer = models.IntegerField(min=0, max=1000, initial=1000) offervol = models.IntegerField(min=0, max=3, initial=0) player = ForeignKey( Player ) # creates 1:m relation -> this decision was made by a certain player
class Appreciation( Model): # our custom model inherits from Django's base class "Model" player = ForeignKey( Player, null=True, blank=True ) # creates 1:m relation -> this appreciation was made by a certain player proposition = ForeignKey( Proposition, null=True, blank=True ) # creates 1:m relation -> this appreciation is related to a certain proposition app_player_ID_ingroup = models.IntegerField() note = models.IntegerField(min=Constants.c_min_note, max=Constants.c_max_note) reaction = models.CharField() related_version = models.PositiveIntegerField(initial=999) up_to_date = models.BooleanField(initial=False) def __str__(self): return "Appreciation n°{id}: {reaction}".format(id=self.pk, reaction=self.reaction)
class Order(Model ): # This is a big object. Do we really need all these fields ? # NASDAQ ouch fields o_type = models.StringField(initial=None) token = models.StringField() # DAN side = models.StringField(initial=None) price = models.IntegerField(initial=None) time_in_force = models.IntegerField(initial=None) firm = models.StringField(initial=None) # otree fields timestamp = models.IntegerField(initial=0) status = models.StringField(initial='S') player = ForeignKey(Player, null=True, blank=True) # Other fields for future use. # shares = models.IntegerField(initial=1) # stock_sym1 = models.IntegerField(initial=1280332576) # stock_sym2 = models.IntegerField(initial=538976288) # display = models.StringField(initial='Y') # capacity = models.StringField(initial='P') # iso = models.StringField(initial='N') # intermarket sweep eligibility # min_quantity = models.IntegerField(initial=0) # cross_type = models.StringField(initial='N') # customer_type = models.StringField(initial='R') # time_stage = models.IntegerField(initial=0) # update_staged = models.StringField(initial=None) # time_canceled = models.IntegerField(initial=0) def stage(self): time = nanoseconds_since_midnight() self.time_stage = time self.token, self.firm = tokengen(self.player.id_in_group, self.side, self.player.order_count) self.player.order_count += 1 self.save() self.player.save() def activate(self, time): self.status = 'A' self.timestamp = time self.save() def cancel(self, time): self.status = 'C' self.time_canceled = time self.save() def execute(self, time): self.status = 'X' self.timestamp = time self.save()
class Decision(Model ): # our custom model inherits from Django's base class "Model" player_decision = models.IntegerField(choices=Choices.choices_q123, initial=Choices.choices_q123[0]) related_question = models.CharField(choices=Choices.questions, initial=Choices.questions[0]) player = ForeignKey( Player ) # creates 1:m relation -> this decision was made by a certain player argument = ManyToManyField(Argument) # creates m:m relation
class Bid(Model): """ Stores details of a buyer's bid. Not super useful at the moment given buyer's limited action space, but future-proofs the code somewhat. It also just gives a nice symmetry for how we deal with the two roles. """ total = models.IntegerField(min=Constants.minprice, max=Constants.maxprice) player = ForeignKey(Player) def set_pricedims(self, pricedims): """ set through manual manipulation of fields """ for i in range(self.player.subsession.dims): pd = self.pricedim_set.create(dimnum=i + 1, value=pricedims[i]) pd.save()
class Focus(Model ): # our custom model inherits from Django's base class "Model" whenhappens = models.CharField() whathappens = models.CharField() wherehappens = models.CharField() player = ForeignKey( Player ) # creates 1:m relation -> this decision was made by a certain player def __str__(self): return 'haha'
class Decision(Model ): # our custom model inherits from Django's base class "Model" player = ForeignKey( Player ) # creates 1:m relation -> this decision was made by a certain player argument = ManyToManyField(Argument, limit_choices_to={ 'arg_status': Constants.c_arguments_status[1] }) # creates m:m relation round_number = models.PositiveIntegerField() nb_ETP = models.FloatField(min=0, max=Constants.c_max_nb_ETP, initial=Constants.c_initial_nbETP)
class Proposition( Model): # our custom model inherits from Django's base class "Model" player = ForeignKey( Player, null=True, blank=True ) # creates 1:m relation -> this proposition was made by a certain player prop_player_ID_ingroup = models.IntegerField() text = models.CharField(verbose_name="") type = models.CharField(choices=Constants.c_proposition_types) version = models.PositiveIntegerField(initial=0) average_note = models.FloatField(min=Constants.c_min_note, max=Constants.c_max_note, initial=0) def __str__(self): return "Proposition {type}: {text}".format(type=self.type, text=self.text)
class TransitiveDecision( Model): # our custom model inherits from Django's base class "Model" player = ForeignKey( Player ) # creates 1:m relation -> this decision was made by a certain player argument = ManyToManyField(Argument, limit_choices_to={ 'arg_status': Constants.c_arguments_status[1] }) # creates m:m relation timestamp = models.DateTimeField() round_number = models.PositiveIntegerField() nb_ETP = models.FloatField(min=0, max=Constants.c_max_nb_ETP, initial=0) def save(self, *args, **kwargs): self.timestamp = timezone.make_aware(datetime.now(), timezone.get_default_timezone()) return super(TransitiveDecision, self).save(*args, **kwargs)
class DefendToken(Model): group = ForeignKey(Group, on_delete='CASCADE') number = models.IntegerField() map = models.IntegerField(initial=0) x = models.FloatField(initial=0) y = models.FloatField(initial=0) x2 = models.FloatField(initial=0) y2 = models.FloatField(initial=0) last_updated = models.FloatField(blank=True) slot = models.IntegerField(initial=-1) def to_dict(self): return { "number": self.number, "map": self.map, "x": self.x, "y": self.y }
class TransitiveDecision( Model): # our custom model inherits from Django's base class "Model" player_decision = models.IntegerField(choices=Choices.choices_q123, initial=Choices.choices_q123[0]) related_question = models.CharField(choices=Choices.questions, initial=Choices.questions[0]) timestamp = models.DateTimeField() player = ForeignKey( Player ) # creates 1:m relation -> this decision was made by a certain player argument = ManyToManyField(Argument) # creates m:m relation def save(self, *args, **kwargs): ''' On save, update timestamps ''' self.timestamp = timezone.make_aware(datetime.now(), timezone.get_default_timezone()) return super(TransitiveDecision, self).save(*args, **kwargs)
class FruitOffer(Model): """ Custom data model derived from Django's generic `Model` class. This class defines an offer of fruit with three properties: - amount of available fruit - selling price per item - kind of fruit Additionally, a reference to the seller is stored via a `ForeignKey` to `Player`. """ KINDS = ( ('Apple', 'Apple'), ('Orange', 'Orange'), ('Banana', 'Banana'), ) PURCHASE_PRICES = { 'Apple': c(0.20), 'Orange': c(0.30), 'Banana': c(0.50), } amount = models.IntegerField(label='Amount', min=0, initial=0) # number of fruits available price = models.CurrencyField(label='Price per fruit', min=0, initial=0) kind = models.StringField(choices=KINDS) # easy to add more attributes per fruit, e.g.: #is_organic = models.BooleanField() # if True: organic fruit, else conventional seller = ForeignKey(Player) # creates many-to-one relation -> this fruit is sold by a certain player, a player # can sell many fruits class CustomModelConf: """ Configuration for otreeutils admin extensions. This class and its attributes must be existent in order to include this model in the data viewer / data export. """ data_view = { 'exclude_fields': ['seller_id'], 'link_with': 'seller' } export_data = { 'exclude_fields': ['seller_id'], 'link_with': 'seller' }
class Investor(Model): group = ForeignKey(Group) order_count = models.IntegerField(initial=1) def receive_from_consumer(self, side): s = ('Buy' if side == 'B' else 'Sell') log.info('Investor: %s.' % s) self.invest(side) def invest(self, side): p = (214748.3647 if side == 'B' else 0) order = Order.objects.create(side=side, price=p, time_in_force=0) order.token, order.firm = tokengen(0, order.side, self.order_count) ouch = translate.enter(order) log.debug('Investor sends an order: %s' % order.token) self.group.send_exchange([ouch]) self.order_count += 1 self.save()
class Decision(Model ): # our custom model inherits from Django's base class "Model" REASONS = ( ('dont_know', "Don't know"), ('example_reason', "Example reason"), ('another_example_reason', "Another example reason"), ) value = models.IntegerField() # will be randomly generated player_decision = models.BooleanField() reason = models.CharField(choices=REASONS) player = ForeignKey( Player ) # creates 1:m relation -> this decision was made by a certain player def __str__(self): return 'decision #%d for player %d (participant %d) - value %d'\ % (self.pk, self.player.pk, self.player.participant.id_in_session, self.value)
class Ask(Model): """ Stores details of a seller's ask """ total = models.IntegerField(min=Constants.minprice, max=Constants.maxprice) stdev = models.FloatField(min=0) auto = models.BooleanField( ) # true if this ask was created automatically, else false manual = models.BooleanField( ) # true if this ask was created via maually changing a field, else false player = ForeignKey(Player) # def generate_pricedims(self): # """ set through auto-generation of price dims """ # for i in range(self.player.subsession.dims): # # # pd = PriceDim(ask=self, dimnum=i + 1) # pd = self.pricedim_set.create(dimnum=i + 1) # pd.save() def set_pricedims(self, pricedims): """ set through manual manipulation of fields """ for i in range(self.player.subsession.dims): pd = self.pricedim_set.create(dimnum=i + 1, value=pricedims[i]) pd.save()
class Trial(Model): """ Trial model holds all information for a single trial made by a player. This is a "custom data model" in a 1:n relationship between Player and Trial. It uses an otreeutils "CustomModelConf" for monitoring and exporting the collected data from this model. """ trial = models.IntegerField( ) # trial number in that round for that participant prime = models.StringField() # prime image to be displayed prime_class = models.StringField( ) # class of prime (corresponds to folder name in _static/amp/primes) target = models.StringField() # target image to be displayed target_class = models.StringField( ) # class of target (corresponds to folder name in _static/amp/targets) response_key = models.StringField( ) # response: key that was pressed by participant response_time_ms = models.IntegerField( ) # time it took until key was pressed since either the target is displayed # or *after* the target was displayed, depending on # Constants.allow_input_during_target_presentation player = ForeignKey(Player, on_delete=models.CASCADE ) # make a 1:n relationship between Player and Trial class CustomModelConf: """ Configuration for otreeutils admin extensions. """ data_view = { # define this attribute if you want to include this model in the live data view 'exclude_fields': ['player'], 'link_with': 'player' } export_data = { # define this attribute if you want to include this model in the data export 'exclude_fields': ['player_id'], 'link_with': 'player' }
class PrefDim(Model): value = models.IntegerField(doc="The value of this preference") prefID = models.IntegerField(doc="The ID of this preference") player = ForeignKey(Player)
class Product(Model): #custom model inherits from Django base class "Model". Based off Ask class. """ Stores details of a product """ player = ForeignKey(Player)
class LikeDislike(Model): player = ForeignKey(Player) argument = ForeignKey(Argument) like_choice = models.CharField(choices=Constants.c_likes_dislikes_choices)