Jupyter Notebook中Pymongo连接MongoDB认证失败及CRUD问题
解决Pymongo连接MongoDB的认证与格式化错误
问题概述
在Jupyter Notebook项目中使用Pymongo连接MongoDB执行CRUD操作时,遇到两类核心错误:
- 使用
db.authenticate(username, password)时,报错:'Collection' object is not callable. If you meant to call the 'authenticate' method on a 'Database' object it is failing because no such method exists. - 格式化连接字符串
self.client = MongoClient('mongodb://localhost:27017/' % (username, password))时,出现TypeError: not all arguments converted during string formatting错误
相关代码
AnimalShelterTest.py
import pymongo from pymongo import MongoClient from bson.objectid import ObjectId class AnimalShelter(object): """ CRUD operations for Animal collection in MongoDB """ def __init__(self, username, password): #Initializing the MongoClient. This helps to access the MongoDB databases and collections. connection = pymongo.MongoClient("localhost:27017") db = connection['AAC'] db.authenticate(username, password) #Complete this create method to implement the C in CRUD. def create(self, data): if data is not None: insert = self.database.animals.insert(data) #data should be dictionary else: raise Exception("Nothing to save, because data parameter is empty") #Create method to implement the R in CRUD. def read(self, searchData): if searchData: data = self.database.animals.find(searchData, {"_id": False}) else: data = self.database.animals.find({}, {"_id": False}) return data #Create method to implement U in CRUD. def update(self, searchData, updateData): if searchData is not None: result = self.database.animals.update_many(searchData, {"$set": updateData}) else: return "{}" return result.raw_result #Create method to implement D in CRUD. def delete(self, deleteData): if deleteData is not None: result = self.database.animals.delete_many(deleteData) else: return "{}" return result.raw_result
Jupyter Notebook代码
from jupyter_plotly_dash import JupyterDash import dash import dash_leaflet as dl from dash import dcc from dash import html import pandas as pd import plotly.express as px from dash import dash_table as dt from dash.dependencies import Input, Output, State import os import numpy as np from pymongo import MongoClient from bson.json_util import dumps import base64 #### FIX ME ##### # change animal_shelter and AnimalShelter to match your CRUD Python module file name and class name from AnimalShelterTest import AnimalShelter ########################### # Data Manipulation / Model ########################### # FIX ME change for your username and password and CRUD Python module name username = "aacuser" password = "French" shelter = AnimalShelter(username, password) # class read method must support return of cursor object df = pd.DataFrame.from_records(shelter.read({})) ######################### # Dashboard Layout / View ######################### app = JupyterDash('Project Two') #FIX ME Add in Grazioso Salvare’s logo image_filename = 'Grazioso_Salvare_Logo.png' # replace with your own image encoded_image = base64.b64encode(open(image_filename, 'rb').read()) #FIX ME Place the HTML image tag in the line below into the app.layout code according to your design #FIX ME Also remember to include a unique identifier such as your name or date #html.Img(src='data:image/png;base64,{}'.format(encoded_image.decode())) app.layout = html.Div([ html.Div(id='hidden-div', style={'display':'none'}), html.Center(html.Img(src='data:image/png;base64,{}'.format(encoded_image.decode()))), html.Center(html.B(html.H1('Dashboard'))), html.Hr(), html.Div( #FIXME Add in code for the interactive filtering options. For example, Radio buttons, drop down, checkboxes, etc. dcc.RadioItems( id='filter-type', options=[ {'label': 'Water Rescue', 'value': 'WR'}, {'label': 'Mountain or Wilderness Rescue', 'value': 'MWR'}, {'label': 'Disaster or Individual Tracking', 'value': 'DIT'}, {'label': 'Reset','value':'RESET'} ], value='RESET', labelStyle={'display':'inline-block'} ) ), html.Hr(), dt.DataTable( id='datatable-id', columns=[ {"name": i, "id": i, "deletable": False, "selectable": True} for i in df.columns ], data=df.to_dict('records'), #FIXME: Set up the features for your interactive data table to make it user-friendly for your client #If you completed the Module Six Assignment, you can copy in the code you created here editable=False, filter_action="native", sort_action="native", sort_mode="multi", column_selectable=False, row_selectable="single", row_deletable=False, selected_columns=[], selected_rows=[], page_action="native", page_current= 0, page_size= 10, ), html.Br(), html.Hr(), #This sets up the dashboard so that your chart and your geolocation chart are side-by-side html.Div(className='row', style={'display' : 'flex'}, children=[ html.Div( id='graph-id', className='col s12 m6', ), html.Div( id='map-id', className='col s12 m6', ) ]) ]) ############################################# # Interaction Between Components / Controller ############################################# @app.callback([Output('datatable-id','data'), Output('datatable-id','columns')], [Input('filter-type', 'value')]) def update_dashboard(filter_type): ### FIX ME Add code to filter interactive data table with MongoDB queries if filter_type == 'WR': df = pd.DataFrame(list(shelter.read({'$and': [{'sex_upon_outcome': 'Intact Female'}, {'$or': [ {'breed': 'Labrador Retriever Mix'}, {'breed': 'Chesa Bay Retr Mix'}, {'breed': 'Newfoundland Mix'}, {'breed': 'Newfoundland/Labrador Retriever'}, {'breed': 'Newfoundland/Australian Cattle Dog'}, {'breed': 'Newfoundland/Great Pyrenees'}] }, {'$and': [{'age_upon_outcome_in_weeks': {'$gte': 26}}, {'age_upon_outcome_in_weeks': {'$lte': 156}}] }] }))) elif filter_type == 'MWR': #Grazioso breeds and ages df = pd.DataFrame(list(shelter.read({'$and': [{'sex_upon_outcome': 'Intact Male'}, {'$or': [ {'breed': 'German Shepherd'}, {'breed': 'Alaskan Malamute'}, {'breed': 'Old English Sheepdog'}, {'breed': 'Rottweiler'}, {'breed': 'Siberian Husky'}] }, {'$and': [{'age_upon_outcome_in_weeks': {'$gte': 26}}, {'age_upon_outcome_in_weeks': {'$lte': 156}}] }] }))) #adjusts the read request for the desired dog type and status elif filter_type == 'DRIT': #breeds and ages df = pd.DataFrame(list(shelter.read({'$and': [{'sex_upon_outcome': 'Intact Male'}, {'$or': [ {'breed': 'Doberman Pinscher'}, {'breed': 'German Shepherd'}, {'breed': 'Golden Retriever'}, {'breed': 'Bloodhound'}, {'breed': 'Rottweiler'}] }, {'$and': [{'age_upon_outcome_in_weeks': {'$gte': 20}}, {'age_upon_outcome_in_weeks': {'$lte': 300}}] }] }))) #resets the search no filter elif filter_type == 'RESET': df = pd.DataFrame.from_records(shelter.read({})) columns=[{"name": i, "id": i, "deletable": False, "selectable": True} for i in df.columns] data=df.to_dict('records') return (data,columns) @app.callback( Output('datatable-id', 'style_data_conditional'), [Input('datatable-id', 'selected_columns')] ) def update_styles(selected_columns): return [{ 'if': { 'column_id': i }, 'background_color': '#D2F3FF' } for i in selected_columns] @app.callback( Output('graph-id', "children"), [Input('datatable-id', "derived_viewport_data")]) def update_graphs(viewData): ###FIX ME #### dff = pd.DataFrame.from_dict(viewData) names = dff['breed'].value_counts().keys().tolist() values = dff['breed'].value_counts().tolist() # add code for chart of your choice (e.g. pie chart) # return [ dcc.Graph( figure = px.pie( data_frame = dff, values = values, names = names, color_discrete_sequence=px.colors.sequential.RdBu, width = 800, height = 500 ) ) ] @app.callback( Output('map-id', "children"), [Input('datatable-id', "derived_viewport_data"), Input('datatable-id', 'selected_rows'), Input('datatable-id', 'selected_columns')]) def update_map(viewData, selected_rows, selected_columns): #FIXME: Add in the code for your geolocation chart #If you completed the Module Six Assignment, you can copy in the code you created here. dff = pd.DataFrame.from_dict(viewData) if selected_rows == []: selected_rows = [0] # Austin TX is at [30.75, -97.48] if len(selected_rows) == 1: return [ dl.Map(style={'width':'1000px', 'height': '500px'}, center=[30.75,-97.48], zoom=10, children=[ dl.TileLayer(id="base-layer-id"), #marker with tool tip and popup dl.Marker(position=[(dff.iloc[selected_rows[0],13]), (dff.iloc[selected_rows[0],14])], children=[ dl.Tooltip(dff.iloc[selected_rows[0],4]), dl.Popup([ html.H4("Animal Name"), html.P(dff.iloc[selected_rows[0],9]), html.H4("Sex"), html.P(dff.iloc[selected_rows[0],12]), html.H4("Breed"), html.P(dff.iloc[selected_rows[0],4]), html.H4("Age"), html.P(dff.iloc[selected_rows[0],15]) ]) ]) ]) ] app
报错信息
认证方法报错
TypeError Traceback (most recent call last) Cell In [1], line 32 30 username = "aacuser" 31 password = "French" ---> 32 shelter = AnimalShelter(username, password) 35 # class read method must support return of cursor object 36 df = pd.DataFrame.from_records(shelter.read({})) File ~\Sample Python Code\7-2 Project Two files\AnimalShelterTest.py:13, in AnimalShelter.__init__(self, username, password) 11 connection = pymongo.MongoClient("localhost:27017") 12 db = connection['AAC'] ---> 13 connection.api.authenticate(username, password) File C:\Python\Python311\Lib\site-packages\pymongo\collection.py:3200, in Collection.__call__(self, *args, **kwargs) 3198 """This is only here so that some API misusages are easier to debug.""" 3199 if "." not in self.__name: -> 3200 raise TypeError( 3201 "'Collection' object is not callable. If you " 3202 "meant to call the '%s' method on a 'Database' " 3203 "object it is failing because no such method " 3204 "exists." % self.__name 3205 ) 3206 raise TypeError( 3207 "'Collection' object is not callable. If you meant to " 3208 "call the '%s' method on a 'Collection' object it is " 3209 "failing because no such method exists." % self.__name.split(".")[-1] 3210 ) TypeError: 'Collection' object is not callable. If you meant to call the 'authenticate' method on a 'Database' object it is failing because no such method exists.
连接字符串格式化报错
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In [1], line 32 30 username = "aacuser" 31 password = "French" ---> 32 shelter = AnimalShelter(username, password) 35 # class read method must support return of cursor object 36 df = pd.DataFrame.from_records(shelter.read({})) File ~\Sample Python Code\7-2 Project Two files\AnimalShelter.py:11, in AnimalShelter.__init__(self, username, password) 9 def __init__(self, username, password): 10 #Initializing the MongoClient. This helps to access the MongoDB databases and collections. ---> 11 self.client = MongoClient('mongodb://localhost:27017/' % (username, password)) 12 #where xxxx is your unique port number 13 self.database = self.client['AAC'] TypeError: not all arguments converted during string formatting
解决方案
1. 修复连接字符串格式化错误
原连接字符串未预留占位符,导致格式化失败。正确做法是使用包含用户名和密码的标准MongoDB连接字符串:
# 使用f-string格式化(推荐) self.client = MongoClient(f'mongodb://{username}:{password}@localhost:27017/') # 或旧式格式化 self.client = MongoClient('mongodb://%s:%s@localhost:27017/' % (username, password))
2. 移除无效的db.authenticate调用
Pymongo 3.x及以上版本已不再推荐使用db.authenticate(),而是直接在连接字符串中传入认证信息。同时原代码中connection.api.authenticate属于错误调用(connection.api是Collection对象,并非Database),需删除所有相关认证方法调用。
3. 修复类中self.database未初始化问题
原__init__方法未将数据库对象赋值给实例变量,导致CRUD方法调用self.database时会报错。修改后的__init__方法如下:
def __init__(self, username, password): self.client = MongoClient(f'mongodb://{username}:{password}@localhost:27017/') self.database = self.client['AAC']
4. 修复create方法中的弃用API
Pymongo的insert方法已被弃用,替换为insert_one(单条数据)或insert_many(多条数据):
def create(self, data): if data is not None: insert_result = self.database.animals.insert_one(data) return insert_result.inserted_id is not None else: raise Exception("Nothing to save, because data parameter is empty")
最终修正后的AnimalShelterTest.py
import pymongo from pymongo import MongoClient from bson.objectid import ObjectId class AnimalShelter(object): """ CRUD operations for Animal collection in MongoDB """ def __init__(self, username, password): #Initializing the
相关产品推荐
相关产品推荐

