SQLAlchemy if/not query session already attached - sqlalchemy

I'm getting data from a website that posts scores from high school football and putting it into a Flask project. I'm using Flask-SQLAlchemy and trying to check to see if the Game exists already; if it doesn't I create a new game in the database, if it does exist I just want to update the scores (in case there has been any corrections to the scores since my last import. Here's my code:
"""
Save to Games Table
"""
game = Games.query.filter_by(game_date=g_date, team1_name=t1_name, team1_score=t1_score, team2_name=t2_name, team2_score=t2_score).first()
"""
Need to set it to update scores if game already exists
"""
if not game:
add_game = Games(year_id=None, team1_id=None, team1_name=t1_name, team1_score=t1_score, team2_id=None, team2_name=t2_name, team2_score=t2_score, game_date=g_date)
db.session.add(add_game)
else:
game.team1_score = t1_score
game.team2_score = t2_score
db.session.add(game)
db.session.commit()
It's giving me this error when I run the code:
sqlalchemy.exc.InvalidRequestError: Object '' is already attached to session '1' (this is '2')
What would be the correct way to do this?

There is no need to add an object to the session, if it was obtained from a query.
game = Games.query.filter_by(...).first()
if not game:
add_game = Games(...)
db.session.add(add_game)
else:
game.team1_score = t1_score
game.team2_score = t2_score
db.session.commit()

Related

Automation script: Get value from related table

I'm trying to break this problem down into manageable parts: Spatial Query.
I want to create an automation script that will put a work order's LatitudeY coordinate in the work order's DESCRIPTION field.
I understand that a work order's coordinates are not stored in the WORKORDER table; they're stored in the WOSERVICEADDRESS table.
Therefore, I believe the script needs to reference a relationship in the Database Configuration application that will point to the related table.
How can I do this?
(Maximo 7.6.1.1)
You can get the related Mbo and get the values from the related Mbo and use it as shown in the below code. By getting the related Mbo you can also alter it's attributes.
from psdi.mbo import MboConstants
serviceAddressSet = mbo.getMboSet("SERVICEADDRESS")
if(serviceAddressSet.count() > 0):
serviceAddressMbo = serviceAddressSet.moveFirst()
latitudeY = serviceAddressMbo.getString("LATITUDEY")
longitudeX = serviceAddressMbo.getString("LONGITUDEX")
mbo.setValue("DESCRIPTION","%s, %s" % (longitudeX, latitudeY),MboConstants.NOACCESSCHECK)
serviceAddressSet.close()
I've got a sample script that compiles successfully:
from psdi.mbo import MboConstants
wonum = mbo.getString("WONUM")
mbo.setValue("DESCRIPTION",wonum,MboConstants.NOACCESSCHECK)
I can change it to get the LatitudeY value via the SERVICEADDRESS relationship:
from psdi.mbo import MboConstants
laty = mbo.getString("SERVICEADDRESS.LatitudeY")
longx = mbo.getString("SERVICEADDRESS.LONGITUDEX")
mbo.setValue("DESCRIPTION",laty + ", " + longx,MboConstants.NOACCESSCHECK)
This appears to work.

Database model custom JSONField values persisting between test cases

I'm using a Django database model to store objects corresponding to a remote ticket service. In testing this model, I'm running several tests to make sure that log messages work correctly for the database model - I'm using Django-nose to run these tests.
The database model looks something like this, using the JSONField from this StackOverflow answer with a small modification to support lists as well as dicts:
class TicketEntity(django.db.models.Model)
tickets = JSONField(null=True, blank=True, default=[], serialize=True)
queued_ticket_data = JSONField(null=True, blank=True, default=[], serialize=True)
...
#classmethod
def create(cls, *args, **kwargs):
instance = cls(*args, **kwargs)
instance.save()
return instance
def queue_output_for_ticket(self, log_data):
self.queued_ticket_data += [log_data]
self.save()
def push_ticket(self):
self.tickets += [self.queued_ticket_data]
self.queued_ticket_data = []
self.save()
return True
The tests (in the order they appear to get run) look like this:
def test_ticket_entity_push_ticket(self):
entity = TicketEntity.create()
entity.queue_output_for_ticket("log output")
entity.queue_output_for_ticket("more log output")
entity.push_ticket()
self.assertEquals(entity.tickets, [[log_data, log_data_1]])
self.assertFalse(entity.queued_ticket_data)
def test_ticket_entity_queue_output_for_ticket(self):
entity = TicketEntity.create()
log_data = "Here's some output to log.\nHere's another line of output.\nAnd another."
entity.queue_output_for_ticket(log_data)
self.assertEquals(entity.queued_ticket_data, [log_data])
The first test passes, perfectly fine. The second test fails on that assert statement, because the entity.queued_ticket_data looks like this:
["log output",
"more log output",
"Here's some output to log.\nHere's another line of output.\nAnd another."]
Those first two elements are there at the very start of the test, immediately after we call TicketEntity.create(). They shouldn't be there - the new instance should be clean because we're creating it from scratch.
Similarly, tickets is pre-filled as well. The TicketEntity has other fields that are not JSONFields, and they do not seem to exhibit this problem.
Can someone shed some light on why this problem might be happening, and what kind of modification we'd need for a fix?

How do you update an MTurk worker qualification score with boto3?

The older MTurk API (and boto2) had an UpdateQualificationScore method that would allow users to update the score of a specific worker, but this seems to have disappeared in the latest version(s) based on boto3.
The latest MTurk API has a GetQualificationScore method (which actually returns a full worker qualification record, not just the score), but no corresponding UpdateQualificationScore method. What is the mechanism to update a score for an existing worker?
As best as I can tell, the proper way to do this with the boto3 is to use the AssociateQualificationWithWorker endpoint:
session = boto3.Session(profile_name='mturk')
client = session.client('mturk')
response = client.associate_qualification_with_worker(
QualificationTypeId=qualification_type_id,
WorkerId=worker_id,
IntegerValue=score,
SendNotification=False,
)
This seems to work, especially when taken alongside GetQualificationScore returning the "full" qualification record instead of just the score.
ex-nerd's answer is correct. Building off the Python sample available at http://requester.mturk.com/developer, the following works to assign a QualificationType then change the score for that Worker:
import boto3
region_name = 'us-east-1'
aws_access_key_id = 'YOUR_ACCESS_ID'
aws_secret_access_key = 'YOUR_SECRET_KEY'
endpoint_url = 'https://mturk-requester-sandbox.us-east-1.amazonaws.com'
# Uncomment this line to use in production
# endpoint_url = 'https://mturk-requester.us-east-1.amazonaws.com'
client = boto3.client(
'mturk',
endpoint_url=endpoint_url,
region_name=region_name,
aws_access_key_id=aws_access_key_id,
aws_secret_access_key=aws_secret_access_key,
)
# This will assign the QualificationType
client.associate_qualification_with_worker(QualificationTypeId = '3KIOU9ULHKIIS5OPUVORW7OE1070V0', WorkerId = 'A39ECJ12CY7TE9', IntegerValue = 100)
# This will set the QualificationScore from 100 to 90
client.associate_qualification_with_worker(QualificationTypeId = '3KIOU9ULHKIIS5OPUVORW7OE1070V0', WorkerId = 'A39ECJ12CY7TE9', IntegerValue = 90)

How to use django TransactionMiddleware with MySQL database

In one of the projects I am working on, I am using the transactions explicitly as follows:
from django.db import transaction
#transaction.commit_on_succcess
def some_view(request):
""" Renders some view
"""
I am using Django 1.5.5 and in the docs it says:
The recommended way to handle transactions in Web requests is to tie them to the request and response phases via Django’s TransactionMiddleware.
It works like this: When a request starts, Django starts a transaction. If the response is produced without problems, Django commits any pending transactions. If the view function produces an exception, Django rolls back any pending transactions.
To activate this feature, just add the TransactionMiddleware middleware to your MIDDLEWARE_CLASSES setting:
I want to use the transactions on requests instead of tying them to a particular view that requires it but I am a little confused about how this'd work. Say I have a view as follows:
def some_view(request):
""" Creates a user object.
"""
context = {}
first_name = request.POST['first_name']
last_name = request.POST['last_name']
email = request.POST['email']
try:
create_user(first_name, last_name, email)
context['success'] = 'User %s was added to the database.' % (first_name)
except IntegrityError, err:
context['failure'] = 'An error occurred while adding user to the database: %s' % (str(err))
except Exception, err:
context['failure'] = '%s' % (str(err))
return json_response(context)
In the above view we are handling the exceptions and returning a response and in the docs it states:
If the response is produced without problems, Django commits any pending transactions.
Q: Will the transactions be committed in the above mentioned view even if it raises an exception ?
What if we want to create multiple objects in a single request and only want to rollback a single entry that raises an exception but commit all other ? So for example, we read a data from the file and for each row we want to create a user object, we want all the users to be inserted into the database except for the ones that raise an error:
def some_view(request):
""" Creates a user object.
"""
context = {}
data = # Read from file
for row in data:
first_name, last_name, email = row.split(",")
try:
create_user(first_name, last_name, email)
context['success'] = 'User %s was added to the database.' % (first_name)
except IntegrityError, err:
context['failure'] = 'An error occurred while adding user to the database: %s' % (str(err))
except Exception, err:
context['failure'] = '%s' % (str(err))
return json_response(context)
Q: How would the transactions work in this case ? Is it better to explicitly use transactions here ?
Update:
In my case I am using an Inherited model class. Example:
class BaseUser(models.Model)
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
email = models.EmailField(max_length=100, unique=True)
class UserA(BaseUser):
phone = models.BigIntegerField()
type = models.CharField(max_length=32)
So in case I am trying to create a UserA type object using the above view and it raises an exception, The BaseUSer object is created with the given data but UserA type object is not. So, what I am trying to do is to either create the TypeA object or do not commit any changes. Currently I am using transactions manually (as follows) and it seem to work fine, It's just that I want to switch to using transactions on HTTP requests instead.
from django.db import transaction
transaction.commit_on_success()
def some_view(request):
""" Creates a user object.
"""
context = {}
data = # Read from file
for row in data:
first_name, last_name, email = row.split(",")
try:
sid = transaction.savepoint()
create_user(first_name, last_name, email)
context['success'] = 'User %s was added to the database.' % (first_name)
transaction.savepoint_commit()
except IntegrityError, err:
context['failure'] = 'An error occurred while adding user to the database: %s' % (str(err))
transaction.savepoint_rollback()
except Exception, err:
transaction.savepoint_rollback()
context['failure'] = '%s' % (str(err))
return json_response(context)
You don't need transactions at all here. If an IntegrityError is raised, that means the database update couldn't even be done, so there is nothing to roll back.
Transactions are useful if you want to roll back all the updates if a single one fails.

PYQT : qCombobox displaying Column "Name" but passing Column "ID"

I've been trying very hard to get this working but so far haven't found the correct route.
I am using pyqt, and I am querying a MySql DataBase, collecting from it a model with all the columns. Until here it's all good..
I've created a combobox that is displaying the correct text using model.setcolumn(1)
What I need now is for this combobox to send on "activated" the relative unique ID of this record, so I am able to create a category relatioship.
What exactly is the best way to do this? I feel I've arrived to a dead end, any help would be appreciated.
Best,
Cris
Best way would be sub-classing QComboBox. You can't override the activated signal but you can create a custom signal that will also be emitted with ID whenever activated is emitted. And you can connect to this signal and do your stuff. It will be something like this:
class MyComboBox(QtGui.QComboBox):
activatedId = QtCore.pyqtSignal(int) #correct this if your ID is not an int
def __init__(self, parent=None):
super(MyComboBox, self).__init__(parent)
self.activated.connect(self.sendId)
#QtCore.pyqtSlot(int)
def sendId(self, index):
model = self.model()
uniqueIdColumn = 0 # if ID is elsewhere adjust
uniqueId = model.data(model.createIndex(index,uniqueIdColumn,0),QtCore.Qt.DisplayRole)
self.activatedId.emit(uniqueId)
Edit
Here is a similar version without Signals. This will return uniqueId whenever you call sendId with an index of the combobox.
class MyComboBox(QtGui.QComboBox):
def __init__(self, parent=None):
super(MyComboBox, self).__init__(parent)
def sendId(self, index):
model = self.model()
uniqueIdColumn = 0 # if ID is elsewhere adjust
uniqueId = model.data(model.createIndex(index,uniqueIdColumn,0),QtCore.Qt.DisplayRole)
return uniqueId