2013-12-16 15 views
7

Ich arbeite mit Mongoengine und versuche, eine einfache Migration zu tun. Ich habe ein Feld, das ich von einem StringField zu einem ReferenceField zu einem anderen Objekt migrieren möchte. Ich plante, die Migration von Hand durchzuführen, zuerst das neue Objekt basierend auf dem String zu konstruieren, der vom alten StringField kommt, und es dann explizit zu setzen.Migrationen in Mongoengine: InvalidId

Das Problem ist, dass ich nicht einmal auf eines der Top-Level-Dokumente zugreifen kann, nachdem ich den Feldtyp geändert habe. Ist es erforderlich, ein "Dummy" -Feld im Klassencode meines Dokuments als Platzhalter für das neue Feld zu erstellen? Das scheint mir kludgy, also nehme ich an, es gibt einen besseren Weg?

Hier ist der Fehler, weil das Feld aus dem DB (StringField) nicht mit einem Referenzfeld übereinstimmt.

/usr/lib/python2.7/site-packages/mongoengine/queryset/base.pyc in __getitem__(self, key) 
    149     return queryset._get_as_pymongo(queryset._cursor.next()) 
    150    return queryset._document._from_son(queryset._cursor[key], 
--> 151             _auto_dereference=self._auto_dereference) 
    152   raise AttributeError 
    153 

/usr/lib/python2.7/site-packages/mongoengine/base/document.pyc in _from_son(cls, son, _auto_dereference) 
    568     try: 
    569      data[field_name] = (value if value is None 
--> 570           else field.to_python(value)) 
    571      if field_name != field.db_field: 
    572       del data[field.db_field] 

/usr/lib/python2.7/site-packages/mongoengine/fields.pyc in to_python(self, value) 
    935   not isinstance(value, (DBRef, Document, EmbeddedDocument))): 
    936    collection = self.document_type._get_collection_name() 
--> 937    value = DBRef(collection, self.document_type.id.to_python(value)) 
    938   return value 
    939 

/usr/lib/python2.7/site-packages/mongoengine/base/fields.pyc in to_python(self, value) 
    390  def to_python(self, value): 
    391   if not isinstance(value, ObjectId): 
--> 392    value = ObjectId(value) 
    393   return value 
    394 

/usr/lib/python2.7/site-packages/bson/objectid.pyc in __init__(self, oid) 
    88    self.__generate() 
    89   else: 
---> 90    self.__validate(oid) 
    91 
    92  @classmethod 

/usr/lib/python2.7/site-packages/bson/objectid.pyc in __validate(self, oid) 
    192      raise InvalidId("%s is not a valid ObjectId" % oid) 
    193    else: 
--> 194     raise InvalidId("%s is not a valid ObjectId" % oid) 
    195   else: 
    196    raise TypeError("id must be an instance of (%s, %s, ObjectId), " 

InvalidId: Was Dirty: a2111fe89383bb562738b81c2b63fe78e877ed32 is not a valid ObjectId 

Antwort

0

ich immer Dinge von Hand migriert habe eine Zwischen Sammlung oder ein Zwischenfeld in der gleichen Sammlung verwenden, aber this example macht es so aussehen wie Sie nicht haben. Stack-Überlauf hasst externe Links, also füge ich das Beispiel wörtlich unten ein. BTW sei vorsichtig mit diesem "Drop_Collection" -Teil!

import unittest 
from mongoengine import * 


class Test(unittest.TestCase): 

    def setUp(self): 
     conn = connect(db='mongoenginetest') 

    def create_old_data(self): 
     class Person(Document): 
      name = StringField() 
      age = FloatField() # Save as string 

      meta = {'allow_inheritance': True} 

     Person.drop_collection() 

     Person(name="Rozza", age=35.00).save() 

     rozza = Person._get_collection().find_one() 
     self.assertEqual(35.00, rozza['age']) 

    def test_migration(self): 

     self.create_old_data() 

     class Person(Document): 
      name = StringField() 
      age = StringField() 

      meta = {'allow_inheritance': True} 

     for p in Person.objects: 
      p.age = "%s" % p.age 
      p.save() 

     rozza = Person.objects.first() 
     self.assertEqual("35.0", rozza.age) 

if __name__ == '__main__': 
    unittest.main() 
0

Die 2 Optionen, die ich für die Migration Skript vorschlagen würde:

  • mit Dynamic Sie Sie ObjectIDs erlauben wandern müssen sollte auf dem Feld und speichern zurück DBRefs
  • tun die Migration in pymongo lesen direkt (die Sammlung von pymongo ist über Person._get_collection() zugänglich) und die Elemente durchlaufen, wobei & gespeichert wird