Как написать класс peewee, который успешно инициализирует другие объекты peewee во время своей собственной инициализации? - PullRequest
0 голосов
/ 02 июня 2018

У меня есть следующие классы:

class B(Base_Model):
    b_attribute_1 = peewee.TextField(null=True)
    a = peewee.ForeignKey(A, null=True)

class A(Base_Model):
    a_attribute_1 = peewee.IntegerField(null=True)
    a_attribute_2 = peewee.DoubleField(null=True)
    class Meta:
        friend_server_address = "103.11.399.002"
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.save()
        from B import B
        # Option (1) -- semi-works: creates incomplete object b,
        #               a is initialised correctly.
        B.create(a=self)
        # Option (2) -- does not work: b is created successfully,
        #               a not created, giving KeyError = "ba1".
        # B.create(b_attribute_1 = kwargs["ba1"], a=self)
        return

Я вижу проблемы, описанные в комментариях к коду (см. Варианты 1 и 2), путем тестирования кода:

class test_a_and_b(unittest.TestCase):
    def setUp(self):
        config.database.init("test.db")
        config.database.create_tables([A, B])
        A(a_attribute_1 = 9705,
          a_attribute_2 = 0.77,
          ba1 = "this is b")
        # This is the breakpoint where I study objects in memory.
        pdb.set_trace()
        return
    def tearDownModule()
        A.get().delete_instance(recursive=True, delete_nullable=True)  
        B.get().delete_instance(recursive=True, delete_nullable=True)
        config.database.drop_tables([A, B])
        os.remove("test.db")

Итакв зависимости от выбора, который я выбрал в __init__ моего A I (после вызова A.get() и B.get() в точке останова), можно увидеть, что либо завершено a, либо неполное b создано, либо просто завершено b и сообщение об ошибке KeyError:"ba1". Мне нужны два полных объекта (строки базы данных) a и b.

Я попытался заглянуть в библиотеку peewee, похоже, что их Model использует __new__, я не видел никаких __init__, поэтому, возможно, здесь кроется моя проблема.Пробовал разные комбо в моем A, но это вроде не помогло.Также попытался использовать инициализацию, определить атрибуты программно и .save() вместо .create() для b, но это тоже не помогло.

1 Ответ

0 голосов
/ 02 июня 2018

Уверен, что проблема, с которой вы столкнулись, заключается в том, что вы не всегда будете включать ba1, когда вам нужен экземпляр A. Только тогда, когда вы создаете новый, вы будете передавать в ba1.,Когда вы выбираете один или когда peewee внутренне создает экземпляр при обращении к нему из B, ваш ключевой аргумент «ba1» не будет там, и ваш код потерпит неудачу с ошибкой, которую вы получаете.

Проверьте наличие 'ba1' перед его использованием (так как вы будете использовать его только тогда, когда создаете новый A самостоятельно).Другими словами, попробуйте это:

import peewee
import unittest

database_proxy = peewee.Proxy()
class BaseModel(peewee.Model):
    class Meta:
        database = database_proxy

class A(BaseModel):
    a_attribute_1 = peewee.IntegerField(null=True)
    a_attribute_2 = peewee.IntegerField(null=True)
    def __init__(self, *args, **kwargs):
        super(A, self).__init__(*args, **kwargs)
        if "ba1" in kwargs:
            self.save()
            B.create(a=self, b_attribute_1 = kwargs["ba1"])

class B(BaseModel):
    b_attribute_1 = peewee.TextField(null=True)
    a = peewee.ForeignKeyField(A, null=True)

class test_a_and_b(unittest.TestCase):
    def setUp(self):
        db = peewee.SqliteDatabase(':memory:')
        database_proxy.initialize(db)
        db.create_tables([A, B])
        A(a_attribute_1 = 9705,
          a_attribute_2 = 0.77,
          ba1 = "this is b")

    def test_a(self):
        b = B.select().where(B.b_attribute_1 == 'this is b').get()
        self.assertEqual(b.b_attribute_1, 'this is b')
        self.assertEqual(b.a.a_attribute_1, 9705)


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