SOLVED:
This works:
print("\nTrying to access by embedded_doc__embedded_int=1:")
for data in Doc.objects(embedded_doc__embedded_int=1):
print(data)
You have to access subclass fields by using the main class variable name (not the class name), followed by __, followed by the subclass variable name, as above.
UPDATE:
My original question is below. I wrote an example to show in condensed and complete form what I'm trying to do.
In this example, I have a Doc class. Each Doc has an Embedded class called "embedded_doc". And within the Embedded class is an integer called "embedded_int".
My goal is to store Docs in MongoDB via MongoEngine, and query the database for Docs that have embedded_doc.embedded_int == 1. So far I haven't been able to figure out how.
class Embedded(EmbeddedDocument):
embedded_int = IntField()
def __eq__(self, other):
return other == self.embedded_int
def __str__(self):
return(str(self.embedded_int))
class Doc(Document):
doc_str = StringField()
embedded_doc = EmbeddedDocumentField(Embedded)
def __str__(self):
return f"{self.doc_str} {str(self.embedded_doc)}"
data1 = Doc(doc_str = "first", embedded_doc = Embedded(embedded_int = 1))
data2 = Doc(doc_str = "second", embedded_doc = Embedded(embedded_int = 2))
#Gives correct output:
#Showing Doc objects in database:
#first 1
#second 2
print("Showing Doc objects in database:")
for data in Doc.objects():
print(data)
#Gives correct output:
#Trying to access by doc_str='first':
#first 1
print("\nTrying to access by doc_str='first':")
for data in Doc.objects(doc_str='first'):
print(data)
#ValueError: The source SON object needs to be of type 'dict' but a '<class 'int'>' was found
#During handling of the above exception, another exception occurred:
#mongoengine.errors.InvalidQueryError: Querying the embedded document 'Embedded' failed, due to an invalid query value
#print("\nTrying to access by embedded_doc=1:")
#for data in Doc.objects(embedded_doc=1):
# print(data)
#SyntaxError: expression cannot contain assignment, perhaps you meant "=="?
#print("\nTrying to access by embedded_doc.embedded_int=1:")
#for data in Doc.objects(embedded_doc.embedded_int=1):
# print(data)
#NameError: name 'embedded_doc' is not defined
#print("\nTrying to access by embedded_doc.embedded_int==1:")
#for data in Doc.objects(embedded_doc.embedded_int==1):
# print(data)
#SyntaxError: expression cannot contain assignment, perhaps you meant "=="?
#print("\nTrying to access by Embedded.embedded_int=1:")
#for data in Doc.objects(Embedded.embedded_int=1):
# print(data)
#Runs, but gives incorrect output:
#Trying to access by Embedded.embedded_int==1:
#first 1
#second 2
print("\nTrying to access by Embedded.embedded_int==1:")
for data in Doc.objects(Embedded.embedded_int==1):
print(data)
ORIGINAL QUESTION:
I'm using Python + MongoDB + MongoEngine to get started with a NoSQL database.
I have a class, Article, which contains a field ArticleMetadata. In turn, ArticleMetadata contains a field called pub_year. I want to query my database for Articles that contain ArticleMetadata with pub_year == 2002. I'm trying this:
for article in Article.objects(ArticleMetadata.pub_year == 2002):
print(article)
input()
But it's printing every article in the database, not just the ones with pub_year == 2002. What do I need to change?
Try ArticleMetadata__pub_year = 2002 instead of ArticleMetadata.pub_year == 2002
Related
I am new to python, here is the first part of my graduation project. I want to extract data from MySql 'insert' statements
if tableName == 'accounts':
a = Account(rm_apostrophe(slippedMsgs[0]), rm_apostrophe(slippedMsgs[1]),
rm_apostrophe(slippedMsgs[2]))
print(a.account_id, a.account_name, a.customer_code)
Accounts.append(a)
In the code above, Account is a class used to save data, rm_apostrophe is a method for handle strings.
class Account:
def __init__(self, account_id, account_name, customer_code):
self.account_id = account_id
self.account_name = account_name
self.customer_code = customer_code
def rm_apostrophe(raw_data):
if raw_data is None or raw_data == "Null":
return None
elif raw_data.startswith("'"):
return raw_data[1:-1]
else:
return raw_data
Account is a simple method with only three attributes, so there is no problem with writing this way.
But I have another class named Ticket with 73 attributes, which means that I have to do rm_apostrophe(slippedMsgs[x]) 73 times in
t = Ticket(rm_apostrophe(slippedMsgs[0]), rm_apostrophe(slippedMsgs[1]),
rm_apostrophe(slippedMsgs[2])...etc)
I guess there should be an easier way to help me pass in these parameters, maybe I need to modify the constructor. Hope someone can help me, thank you very much
You can use a list comprehension to create the list of arguments:
args = [rm_apostrophe(x) for x in slippedMsgs]
Then you can pass these arguments using t = Ticket(*args)
The * before the args passes every item in the list as an argument to Ticket
I started working with flask-python recently.
I am trying to send an array read from the database to a class that defines a form.
Here is my class :
# livraison Form Class
class livraisonForm(Form):
list_assurances=['-', u'Aucune assurance trouvée']
type_assur = SelectField(u'Type d\'assurance', choices=list_assurances)
# INIT function :
def __init__(self, list_assurances, *args, **kwargs):
super(Form)
self.list_assurances = list_assurances
Here is how I am trying to pass the array to the init function
def add_livraison():
form = livraisonForm(request.form, get_assurances())
the get_assurances() function returns an array as mentionned below :
def get_assurances():
# Create db cursor
cur = mysql.get_db().cursor()
# Get user by username
result = cur.execute("SELECT ID_ASSURANCE, DESCRIPTION FROM type_assurance ")
if result > 0:
# Get assurances list
data = cur.fetchone()
# Close connection
cur.close()
return [(i[0]+'', i[1]+'') for i in data]
# Close connection
cur.close()
return ['-', u'Aucun assur trouvée']
unfortunately, I am having this problem concerning the form class :
TypeError: 'UnboundField' object is not callable
I tried to delete the list_assurances variable from the form and called the function directly but I got a problem saying that the database has no attribute cursor.
I would like to know what is the right way to send an array to a class -form class- in flask.
Thank you so much
form = livraisonForm(request.form, get_assurances())
Here you're actually assigning the request.form to the self.assurances, not get_assurances() as you should.
Try it like that:
form = livraisonForm(get_assurances())
Sorry this is the second post in two days.. I am pulling my hair out with this. I am attempting to take data from reddit and put it into an array in a way I can pull the data out later for tensorflow to parse it. Now the issue is my second object inside of the other object is not giving me whats inside it... "<main.Submission" why am I getting this back?
Goals of this post:
1: Why am I getting <main.Submission> and how should I be doing this.
File "C:/automation/git/tensorflow/untitled0.py", line 35, in <module>
submissions[sm.id].addSubSubmission(Submission.addComment(cmt.id, cmt.author.name, cmt.body))
TypeError: addComment() missing 1 required positional argument: 'body'
Sorry for the long winded and most likely basic questions. Going from powershell to python was not as straight forward as I thought..
Thanks
Cody
import praw
# sets log in data for session
reddit = praw.Reddit(client_id='bY',
client_secret='v9',
user_agent='android:com.example.myredditapp:'
'v1.2.3 (by /u/r)')
class Submission(object):
def __init__(self, id, title, author):
self.id = id
self.title = title
self.subSubmission = {}
self.author = author
def addComment(self, id, author, body):
self.id = id
self.author = author
self.body = body
def addSubSubmission(self,submission):
self.subSubmission[submission,id] = submission
def getSubSubmission(self,id):
return self.subSubmission[id]
submissions = {}
for sm in reddit.subreddit('redditdev').hot(limit=2):
# pulls the ID and makes that the head of each
submissions[sm.id] = Submission(sm.id, sm.title, sm.author.name)
mySubmission = reddit.submission(id=sm.id)
mySubmission.comments.replace_more(limit=0)
# Get all the comments and first post and list their id author and body(comment)
for cmt in mySubmission.comments.list():
submissions[sm.id].addSubSubmission(Submission.addComment(cmt.id, cmt.author.name, cmt.body))
# My trying to read what all there??!? ##
for key in submissions.keys():
value = submissions[key]
print(key, "=", value)
for key, value in submissions.items():
print(key, "=", value)
expecting to see:
{Title = test {comment.id = 1111 {Comment = 'blah', Author = 'Bob'}}
{comment.id = 1112 {Comment = 'blah2', Author = 'Bob2'}}
}
It is giving you back the entire Submission object - but then you're printing it. How should a submission object look on screen when printed? This is something you can define in the Submission class - check out the first answer in this post: Difference between __str__ and __repr__ in Python
To explain this further: python doesn't know how to represent a class on screen. Sure, the class has attributes that are strings, lists, dicts etc, but python knows how to print those. Your class you just created? What's important? What should be printed? python doesn't know this, and is smart enough not to make any assumptions.
If you add a __repr__ function to your class, python will call it and print whatever that function returns.
Very new to Python and could do with some help. How do I go about referencing members in a class?
I have two csv files. One contains a series of parts and associated material ID. The other is a material index that contains materials ID's and some information about that material.
My intention is to create a third file that contains all of the parts, their material Id's and the information if present in the material index.
I have created a class for the material index and am trying to access objects in this class using material Ids from the part file however, this is not working and I am unsure as to why. Any help is appreciated:
class material():
def __init__(self, name, ftu, e, nu):
self.name = name
self.ftu = ftu
self.e = e
self.nu = nu
def extract_FTU_Strain(input_file_parts,input_file_FTU,output_file):
parts = {}
materials = {}
for aline in open(input_file_FTU, 'r'):
comma_split = aline.strip().split(',')
name = comma_split[1]
ftu = comma_split[8]
e = comma_split[9]
nu = comma_split[7]
try:
materials[int(comma_split[0])] = material(comma_split[1],comma_split[8],comma_split[9],comma_split[7])
#materials[comma_split[0]] = material(comma_split[1],comma_split[8],comma_split[9],comma_split[7])
except:
pass
for i in open(input_file_parts, 'r'):
semicolon_split = i.strip().split(';')
material_id = semicolon_split[3]
part = semicolon_split[0]
part_id = semicolon_split[1]
material_name = materials[material_id].name
FTU = materials[material_id].ftu
Stress = materials[material_id].e
output.write(','.join([part,part_id,material_name,material_id,FTU,Stress]) + '\n')
output = open (output_file,'w')
output.write('Part Title, Part Id, Material Id, FTU, e' + '\n')
output.close()
import sys
input_file_parts = '/parttable.csv'
input_file_FTU = '/Material_Index.csv'
output_file = '/PYTHONTESTING123.csv'
extract_FTU_Strain(input_file_parts,input_file_FTU,output_file)
Since in the comments you said your error is in materials[material_id] make material_id an integer as it was an integer when you created the object.
You created it this way
materials[int(comma_split[0])]=...
But later called it without converting material_id to an int. Do this before calling it in your for loop to write in the output.
material_id = int(material_id)
I may have misinterpreted your question, but going off the line 'How do I go about referencing members in a class?' you can reference member variables like so:
class Demonstration:
def __init__(self, a, b):
self.a = a
self.b = b
def printMembers(self):
print self.a, self.b
So inside the class you can use self.someVariable to reference member variables.
If you want to access them outside of the class:
myclass.myvariable
I'll happily edit the answer if I have't quite understood your question or if there is a specific error you are getting.
I did not understand what error you have, could you put the traceback? Anyway, you are creating a class instance at the time of assignment. For more elegant programming, you could simply do:
m = materials(name, ftu, e, nu)
This way you can access the instance variables like this:
m.name
m.ftu
...
And try, except -> pass it's very dangerous
I am trying to get the user to make an object called a NoteSet, each NoteSet will be put into a global list called db. This is my attempt at making this:
import sys
import datetime
db = list()
class NoteSet:
nextseqNum = 0
def __init__(self,name,description,hidden):
global db
self.seqNum = Note.nextseqNum
self.name = name
self.description = description
self.dateCreated = datetime.date.today()
self.hidden = hidden
self.notes = list()
db[self.seqNum] = self
print(self)
print(len(db))
Note.nextseqNum += 1
When I try to create an object for example:
NoteSet('example','ex',True)
It gives me the error
Traceback (most recent call last):
File "", line 1, in
NoteSet('example','ex',True)
File "C:\Users\Brandon\Desktop\step5.py", line 22, in init
db[self.seqNum] = self
IndexError: list assignment index out of range
Is this the right way to make a global list of objects?
As #aruisdante said you will need to append to the list
Try this:
db = []
class ListObj:
def __init__(self, name, msg, hide=False):
self.name = name
self.msg = msg
self.hide = hide
db.append(self)
Good Luck!
You get this error because db has no elements in it (python lists are initialized to length 0), so when you try and replace the element at location self.seqNum, you are acessing an invalid index. It has nothing to do with the global-ness of it.
If we assume that this global list is only ever going to be accessed in a thread-safe manner, you should simply be able to do:
db.appened(self)
Instead. However, as mentioned in the comments, it makes more sense in this use case to make db a class variable if this class is the 'gate keeper' to interfacing with the db list.
UPDATE
To address the OP's question in the comments,
I am looking to be able to keep track of the location of the objects in the list by the seqNum
As currently written, seqNum will always increment linearly, forever, with each new NoteSet instance. If we assume thread-safe access of Note.nextseqNum, then what you're trying to do via db[self.seqNum] is already implicitly done via db.append(self), because len(db) == Note.nextseqNum, always. For now, we're going to ignore what happens if you cand remove elements from db, because right now your system doesn't account for that at all and would completely break anyway.
If, however, in the future seqNum doesn't just increase monotonically forever each time you make a new instance, you can simply make db a dict instead of a list:
db = dict()
And then insert the new instance to it exactly as you are currently,
db[self.seqNum] = self
db now represents a mapping of a seqNum to a NoteSet explicitly, rather than an implicit relationship based on an array index.
I would actually recommend doing it this way anyway, as it will also solve the problem of removing items from db for 'free'. As is, doing del db[instance.seqNum] will completely invalidate all mappings of seqNum into db for any instance that came after the removed instance. But if db is a dict, then this operation does what you expect it to and all of the seqNum values still map to the correct instance in db.
So, to bring it all together, I would recommend you alter your class to look like the following:
import sys
import datetime
class NoteSet:
nextseqNum = 0
db = dict()
def __init__(self,name,description,hidden):
self.seqNum = NoteSet.nextseqNum
self.name = name
self.description = description
self.dateCreated = datetime.date.today()
self.hidden = hidden
self.notes = list()
NoteSet.db[self.seqNum] = self
print(self)
print(len(db))
NoteSet.nextseqNum += 1