#1 by papayapap (edited )
I am learning to use ExtraModel, so I created a simple example below. Unfortunately, it gives me the error in the title and I am not sure why. StackOverflow answers suggest this comes because an integer (ID) is being interpreted as an ORM object.
Anybody knows that this means in an Otree context?
############### init.py ####################
from otree.api import *
class C(BaseConstants):
NAME_IN_URL = 'store_data'
PLAYERS_PER_GROUP = None
NUM_ROUNDS = 1
NUM_EMPLOYERS = 3
NUM_WORKERS = 7
class Subsession(BaseSubsession):
pass
class Group(BaseGroup):
is_finished = models.BooleanField(initial=False)
job_id = models.IntegerField(initial=0)
class Player(BasePlayer):
is_employer = models.IntegerField()
worker_is_employed = models.IntegerField(initial=0, min=0, max=1)
employer_num_workers = models.IntegerField(initial=0, min=0, max=3)
class JobOffer(ExtraModel):
group = models.Link(Group)
employer_id = models.Link(Player)
wage = models.IntegerField(min=0, max=100)
effort = models.IntegerField(min=0, max=10)
# FUNCTIONS
def creating_session(subsession: Subsession):
players = subsession.get_players()
if subsession.round_number == 1:
for p in players:
if p.id_in_group <= C.NUM_EMPLOYERS:
p.participant.is_employer = True
else:
p.participant.is_employer = False
for p in players:
if p.participant.is_employer:
p.is_employer = 1
else:
p.is_employer = 0
# PAGES
class MyPage(Page):
form_model = 'group'
@staticmethod
def js_vars(player: Player):
return dict(my_id=player.id_in_group, is_employer=player.is_employer)
@staticmethod
def live_method(player: Player, data):
group = player.group
my_id = player.id_in_group
print('Received: ', data)
print(my_id)
if data['information_type'] == 'offer':
# check if offer was legit. If yes...
group.job_id = group.job_id + 1
print(group.job_id)
employer_id = data['employer_id']
wage = data['wage']
effort = data['effort']
JobOffer.create(
group=group,
employer_id=employer_id,
wage=wage,
effort=effort,
)
offer = JobOffer.filter(group=group)
print(offer)
class ResultsWaitPage(WaitPage):
pass
class Results(Page):
pass
page_sequence = [MyPage, ResultsWaitPage, Results]
######################## MyPage
{{ block title }}
<form>
<div class="row">
<div class="col">
<input type="text" id="wage" class="form-control" placeholder="Wage">
</div>
<div class="col">
<input type="text" id="effort" class="form-control" placeholder="Effort">
</div>
<div class="col">
<button type="button" class="btn btn-secondary" id="send_offer" onclick="sendOffer()"> Send Offer </button>
</div>
</div>
</form>
<script>
function sendOffer() {
let offered_wage = parseInt(document.getElementById("wage").value);
let effort_requested = parseInt(document.getElementById("effort").value);
let my_id = parseInt(js_vars.my_id);
} else {
liveSend({
"information_type": "offer",
"employer_id": my_id,
"wage": offered_wage,
"effort": effort_requested
});
document.getElementById("effort").value = "";
document.getElementById("wage").value = "";
}
}
</script>
{{ endblock }}
Full error message:
Exception in ASGI application
Traceback (most recent call last):
File "C:\Users\felix\AppData\Local\Programs\Python\Python39\lib\site-packages\uvicorn\protocols\websockets\websockets_impl.py", line 162, in run_asgi
result = await self.app(self.scope, self.asgi_receive, self.asgi_send)
File "C:\Users\felix\AppData\Local\Programs\Python\Python39\lib\site-packages\uvicorn\middleware\proxy_headers.py", line 45, in __call__
return await self.app(scope, receive, send)
File "C:\Users\felix\AppData\Local\Programs\Python\Python39\lib\site-packages\starlette\applications.py", line 112, in __call__
await self.middleware_stack(scope, receive, send)
File "C:\Users\felix\AppData\Local\Programs\Python\Python39\lib\site-packages\starlette\middleware\base.py", line 21, in __call__
await self.app(scope, receive, send)
File "C:\Users\felix\AppData\Local\Programs\Python\Python39\lib\site-packages\otree\errorpage.py", line 214, in __call__
await self.app(scope, receive, send)
File "C:\Users\felix\AppData\Local\Programs\Python\Python39\lib\site-packages\starlette\middleware\base.py", line 21, in __call__
await self.app(scope, receive, send)
File "C:\Users\felix\AppData\Local\Programs\Python\Python39\lib\site-packages\starlette\middleware\sessions.py", line 75, in __call__
await self.app(scope, receive, send_wrapper)
File "C:\Users\felix\AppData\Local\Programs\Python\Python39\lib\site-packages\otree\patch.py", line 16, in __call__
await self.app(scope, receive, send)
File "C:\Users\felix\AppData\Local\Programs\Python\Python39\lib\site-packages\starlette\routing.py", line 582, in __call__
await route.handle(scope, receive, send)
File "C:\Users\felix\AppData\Local\Programs\Python\Python39\lib\site-packages\starlette\routing.py", line 299, in handle
await self.app(scope, receive, send)
File "C:\Users\felix\AppData\Local\Programs\Python\Python39\lib\site-packages\starlette\endpoints.py", line 74, in dispatch
raise exc from None
File "C:\Users\felix\AppData\Local\Programs\Python\Python39\lib\site-packages\starlette\endpoints.py", line 68, in dispatch
await self.on_receive(websocket, data)
File "C:\Users\felix\AppData\Local\Programs\Python\Python39\lib\site-packages\otree\channels\consumers.py", line 127, in on_receive
await self.post_receive_json(data, **self.cleaned_kwargs)
File "C:\Users\felix\AppData\Local\Programs\Python\Python39\lib\site-packages\otree\channels\consumers.py", line 194, in post_receive_json
await live_payload_function(
File "C:\Users\felix\AppData\Local\Programs\Python\Python39\lib\site-packages\otree\live.py", line 45, in live_payload_function
retval = call_live_method_compat(live_method, player, payload)
File "C:\Users\felix\AppData\Local\Programs\Python\Python39\lib\site-packages\otree\live.py", line 101, in call_live_method_compat
return live_method(player, payload)
File "C:\Users\felix\Documents\Otree\test\testproject\store_data\__init__.py", line 81, in live_method
JobOffer.create(
File "C:\Users\felix\AppData\Local\Programs\Python\Python39\lib\site-packages\otree\database.py", line 912, in create
db.add(obj)
File "C:\Users\felix\AppData\Local\Programs\Python\Python39\lib\site-packages\otree\database.py", line 170, in add
return self._db.add(obj)
File "C:\Users\felix\AppData\Local\Programs\Python\Python39\lib\site-packages\sqlalchemy\orm\session.py", line 2023, in add
self._save_or_update_state(state)
File "C:\Users\felix\AppData\Local\Programs\Python\Python39\lib\site-packages\sqlalchemy\orm\session.py", line 2039, in _save_or_update_state
for o, m, st_, dct_ in mapper.cascade_iterator(
File "C:\Users\felix\AppData\Local\Programs\Python\Python39\lib\site-packages\sqlalchemy\orm\mapper.py", line 3098, in cascade_iterator
queue = deque(
File "C:\Users\felix\AppData\Local\Programs\Python\Python39\lib\site-packages\sqlalchemy\orm\relationships.py", line 1938, in cascade_iterator
tuples = state.manager[self.key].impl.get_all_pending(state, dict_)
File "C:\Users\felix\AppData\Local\Programs\Python\Python39\lib\site-packages\sqlalchemy\orm\attributes.py", line 967, in get_all_pending
ret = [(instance_state(current), current)]
AttributeError: 'int' object has no attribute '_sa_instance_state