I have a list of tuples of foreign keys of the form [(3,2),(2,3)]. And I want to insert the items into a ManyToMany table within a model:
class Place(models.Model):
data=models.IntegerField()
connected_to=models.ManyToManyField('self')
class PlaceMeta(models.Model):
place=models.ForeignKey("places.Place")
and I am inserting the list (connections) with:
places=Place.objects.all()
for conn_1, conn_2 in connections:
for place in places:
if place.data == conn_1 and conn_1 != conn_2:
place.connected_to.add(conn_1, conn_2)
elif place.data == conn_2 and conn_1 != conn_2:
fixture.connected_to.add(conn_2, conn_1)
When I print the list it prints [(3L, 2L),(2L, 3L)] (for example) but after I insert the table shows that (2,2),(3,2),(2,3),and (3,3) have been inserted.
I've tried at multiple points in the code to check for if a tuple (a,a) exists and when I print prior to inserting it shows no such tuple. So how do I avoid inserting such tuples seeing as they don't even appear to exist in the list before I insert?
You have one parameter too much in you call to add(). It should look like this:
if place.data == conn_1 and conn_1 != conn_2:
# place is the Place instance described by conn_1.
# Let's connect it to conn_2!
place.connected_to.add(conn_2)
And you don't need to iterate through all the Places, instead use objects.get or objects.filter depending if data is unique or not. For example, if it is unique, use:
for source, target in connections:
Place.objects.get(data=source).connected_to.add(Place.objects.get(data=target))
(and probably add the unique=True attribute to the data field)
Related
I have a logging system in my discord bot, and I want to make a system which allows you to ignore channels, but I'm stuck with it.
Currently I have this code:
cursor=db.cursor(dictionary=True)
cursor.execute(f"SELECT * FROM `logexclude` WHERE server={int(before.guild.id)}")
excluded = cursor.fetchall()
for i in excluded:
if before.channel.id in i[1]: return
excluded is a list and it looks like this:
[{'server': 890248334542008321, 'channel_ids': 890248758875533322, 'user_ids': 0, 'role_ids': 0}]
However, when I try to access it's first element (excluded[0]), it just gives me an error:
if before.channel.id in i[1]: return
TypeError: 1
Dictionaries store their data in key:value pairs, so you can only access them by key (or value). You can't access them by index, there is the problem.
cursor=db.cursor(dictionary=True)
cursor.execute(f"SELECT * FROM `logexclude` WHERE server=?", (before.guild.id))
excluded = cursor.fetchall()
for i in excluded:
if i['channel_ids'] == before.channel.id:
return
This should work.
P. S. It's better to separate query and parameters using question mark (?), here's described why.
P. S. S. If you want to store multiple channels in channel_id, you should use one-to-many relationship for your database.
I have a list of dictionaries called listCityStateZip. One of the keys in listCityStateZip is called cityStateZip. I want to see which of the cityStateZip values exist in a MongoDB collection called zipcodes (field: citystatezip). If no match is found, then I want to flag that record in my list as "N". If a match is found, I want to flag that record in my list as "Y". I thought the code below would address my issues, but for some reason only the very first record in listCityStateZip (the list) ends up getting a flag. Code shown below. Two questions: 1) is there an easier way to write this code using python and 2) if not, why do I get a flag only in the very first record in my list?
for a in listCityStateZip:
for b in db.zipcodes.find({'citystatezip': a['cityStateZip']},{'_id':1}):
c.append(b)
if len(c) == 0:
a['flag'] = 'N'
else:
a['flag'] = 'Y'
c=[]
You can try this, much easier way
for a in listCityStateZip:
if db.zipcodes.find({'citystatezip': a['cityStateZip']}).count() > 0:
a['flag'] = 'Y'
else:
a['flag'] = 'N'
I'm adding a search feature to my application (created using PyQt5) that will allow the user to search an archive table in the database. I've provided applicable fields for the user to choose to match rows with. I'm having some trouble with the query filter use only what was provided by the user, given that the other fields would be empty strings.
Here's what I have so far:
def search_for_order(pierre):
fields = {'archive.pat.firstname': pierre.search_firstname.text(),
'archive.pat.lastname': pierre.search_lastname.text(),
'archive.pat.address': pierre.search_address.text(),
'archive.pat.phone': pierre.search_phone.text(),
'archive.compound.compname': pierre.search_compname.text(),
'archive.compound.compstrength': pierre.search_compstrength.text(),
'archive.compound.compform': pierre.search_compform.currentText(),
'archive.doc.lastname': pierre.search_doctor.text(),
'archive.clinic.clinicname': pierre.search_clinic.text()
}
filters = {}
for field, value in fields.items():
if value is not '':
filters[field] = value
query = session.query(Archive).join(Patient, Prescribers, Clinic, Compound)\
.filter(and_(field == value for field, value in filters.items())).all()
The fields dictionary collects the values of all the fields in the search form. Some of them will be blank, resulting in empty strings. filters is intended to be a dictionary of the object names and the value to match that.
The problem lies in your definition of the expressions within your and_ conjunction. As of now you're comparing each field with the corresponding value which of course returns false for each comparison.
To properly populate the and_ conjunction you have to create a list of what sqlalchemy calls BinaryExpression objects.
In order to do so I'd change your code like this:
1) First use actual references to your table classes in your definition of fields:
fields = {
(Patient, 'firstname'): pierre.search_firstname.text(),
(Patient, 'lastname'): pierre.search_lastname.text(),
(Patient, 'address'): pierre.search_address.text(),
(Patient, 'phone'): pierre.search_phone.text(),
(Compound, 'compname'): pierre.search_compname.text(),
(Compound, 'compstrength'): pierre.search_compstrength.text(),
(Compound, 'compform'): pierre.search_compform.currentText(),
(Prescribers, 'lastname'): pierre.search_doctor.text(),
(Clinic, 'clinicname'): pierre.search_clinic.text()
}
2) Define filters as a list instead of a dictionary:
filters = list()
3) To populate the filters list explode the tuple of table and fieldname used as key in the fields dictionary and add the value to again create tuples but now with three elements. Append each of the newly created tuples to the list of filters:
for table_field, value in fields.items():
table, field = table_field
if value:
filters.append((table, field, value))
4) Now transform the created list of filter definitions to a list of BinaryExpression objects usable by sqlalchemy:
binary_expressions = [getattr(table, attribute) == value for table, attribute, value in filters]
5) Finally apply the binary expressions to your query, make sure it's presented to the and_ conjunction in a consumable form:
query = session.query(Archive).join(Patient, Prescribers, Clinic, Compound)\
.filter(and_(*binary_expressions)).all()
I'm not able to test that solution within your configuration, but a similar test using my environment was successful.
Once you get a query object bound to a table in SqlAlquemy - that is, what is returned by session.query(Archive) in the code above -, calling some methods on that object will return a new, modified query, where that filter is already applied.
So, my preferred way of combining several and filters is to start from the bare query, iterate over the filters to be used, and for each, add a new .filter call and reassign the query:
query = session.query(Archive).join(Patient, Prescribers, Clinic, Compound)
for field, value in filters.items():
query = query.filter(field == value)
results = query.all()
Using and_ or or_ as you intend can also work - in the case of your example, the only thing missing was an *. Without an * preceeding the generator expression, it is passed as the first (and sole) parameter to and_. With a prefixed *, all elements in the iterator are unpacked in place, each one passed as an argument:
...
.filter(and_(*(field == value for field, value in filters.items()))).all()
I have a list of tables which I would like to iterate and find a specific row based on a foreign key column, then delete it.
This is what my list of tables look like:
subrep_tables = [ TCableResistance.__table__,
TCapacitorBankTest.__table__,
TCapAndDf.__table__,
TMeasuredData.__table__,
TMultiDeviceData.__table__,
TStepVoltage.__table__,
TTemperatureData.__table__,
TTransformerResistance.__table__,
TTransformerTurnsRatio.__table__,
TTripUnit.__table__,
TVectorDiagram.__table__,
TWithstandTest.__table__,
]
I called the list subrep_tables because all of those tables contains a foreign key called ixSubReport.
What I'm trying to do is iterate the list and find all the rows that have a certain sub report and delete those rows instead of going to each table and running the query to delete them(very tedious)
This is what I've come up with thus far.
for report in DBSession.query(TReport).filter(TReport.ixDevice == device_id).all():
for sub_report in DBSession.query(TSubReport).filter(TSubReport.ixReport == report.ixReport).all():
for table in subrep_tables:
for item in DBSession.query(table).filter(table.ixSubReport == sub_report.ixSubReport).all():
print "item: " + str(item)
#DBSession.delete(item)
I'm having some difficulty accessing the table's ixSubReport column for my WHERE clause. The code I have right now gives me an error saying: 'Table' Object has no attribute 'ixSubReport'.
How can I access my iterated table's ixSubReport column to use in my WHERE clause to find the specific row so I can delete it?
If you really want to query the tables, the columns are under the c attribute, use table.c.ixSubReport.
There's no reason to create a list of the __table__ attributes though, just query the models directly. Also, you can avoid a ton of overhead by not performing the first two queries; you can do all this in a single query per model. (This example assumes there are relationships set up between te models).
from sqlalchemy.orm import contains_eager
has_subrep_models = [TCableResistance, TCapacitorBankTest, ...]
# assuming each has_subrep model has a relationship "subrep"
# assuming TSubReport has a relationship "report"
for has_subrep_model in has_subrep_models:
for item in DBSession.query(has_subrep_model).join(has_subrep_model.subrep, TSubReport.report).filter(TReport.ixDevice == device_id).options(contains_eager(has_subrep_model.subrep), contains_eager(TSubReport.report)):
DBSession.delete(item)
This simply joins the related sub report and report when querying each model that has a sub report, and does the filtering on the report's device there. So you end up doing one query per model, rather than 1 + <num reports> + (<num reports> * <num models with sub reports>) = a lot.
Thanks to Denis for the input, I ended up with this :
for report in DBSession.query(TReport).filter(TReport.ixDevice == device_id).all():
for sub_report in DBSession.query(TSubReport).filter(TSubReport.ixReport == report.ixReport).all():
for table in subrep_tables:
for item in DBSession.query(table).filter(table.c.ixSubreport == sub_report.ixSubReport).all():
DBSession.delete(item)
I am working on python plugins.I used PyQt4 Designer.
I want to list query result into QTreeWidget.
My code is as follows:
c = self.db.con.cursor()
self.db._exec_sql(c, "select est from bio")
for row in c.fetchall():
item_value=unicode(row[0])
top_node1 = QTreeWidgetItem(item_value)
self.treeWidget.insertTopLevelItem(0, top_node1)
The query returns the values as:
But when i list these values into QTreeWidget using above code,it is shown as below :
Only first character is shown.If i change '0' to some other number in self.treeWidget.insertTopLevelItem(0, top_node1) ,nothing appears in QTreeWidget.
How do i do it????
thanx.
If you take a look at the documentation for a QTreeWidgetItem, you will see there are a number of possible constructors for creating an instance. Though none of which it seems you are using in a way that is going to give you desirable results. The closest match to the signature you are providing is:
QTreeWidgetItem ( const QStringList & strings, int type = Type )
What this is probably doing is taking your string (I am assuming row[0] is a string because I don't know which drivers you are using) and applying it as a sequence, which would fullfill the requiremets of QStringList. Thus what you are getting is populating multiple columns of your item with each letter of your string value. If this is what you wanted, then you would n eed to tell your widget to show more columns: self.treeWidget.setColumnCount(10). But this isn't what you are looking for I am sure.
More likely what you should be trying is to create a new item, then add the value to the desired column:
item = QTreeWidgetItem()
item.setText(0, unicode(row[0]))
self.treeWidget.insertTopLevelItem(0, item)
You can use the default constructor with no arguments, set the text value of the first column to your database record field value, and then add that item to the tree. You could also build up a list of the items and add them at once:
items = []
for row in c.fetchall():
item = QTreeWidgetItem()
item.setText(0, unicode(row[0]))
items.append(item)
self.treeWidget.insertTopLevelItems(0, items)
Your first aproach could be corrected just add a list to the widgetitem not a string like this:
top_node1 = QTreeWidgetItem([item_value])