【问题标题】:Peewee and Database InheritancePeewee 和数据库继承
【发布时间】:2014-04-30 05:35:22
【问题描述】:

我正在尝试通过制作书籍笔记应用程序来学习 Peewee 和 Bottle。

假设我有以下实体:

Subject
Book
Chapter
Note
Tag

我希望能够为章节、书籍和主题做笔记。

在数据库中,你会这样做:

create table noteable (
    noteable_id INT AUTO_INCREMENT PRIMARY KEY
    ,type VARCHAR(10) NOT NULL CHECK (type in ('SUBJECT','BOOK','CHAPTER','NOTE'))
);
create table subject (
    subject_id INT AUTO_INCREMENT PRIMARY KEY
    ,noteable_id INT UNIQUE REFERENCES noteable (noteable_id)
    ,...
);
create table book (
    book_id INT AUTO_INCREMENT PRIMARY KEY
    ,subject_id INT NOT NULL REFERENCES subject (subject_id)
    ,noteable_id INT UNIQUE REFERENCES noteable (noteable_id)
    ,...
);
create table chapter(
    chapter_id INT AUTO_INCREMENT PRIMARY KEY
    ,book_id INT NOT NULL REFERENCES book (book_id)
    ,noteable_id INT UNIQUE REFERENCES noteable(noteable_id)
    ,...
);

create table note(
    note_id INT AUTO_INCREMENT PRIMARY KEY
    ,noteable_id INT UNIQUE REFERENCES noteable(noteable_id)
    ,...
);

(如果你想要 note 和 notable 之间的 M:N 关系,你也可以做一个 note_notable 桥接表)。

您将在主题、书籍和章节上插入触发器之前将一行插入到 noteable,检索新行的 noteable_id,并将其用于传入行。

我假设如果您使用像 Peewee 这样的 ORM,您会希望在应用程序逻辑中而不是触发器中执行此操作。

如何在 Peewee 中实现这个模型?

【问题讨论】:

    标签: python single-table-inheritance peewee concrete-inheritance


    【解决方案1】:

    这就是我的做法。我在 Peewee 中找不到实现继承的本地方式,所以我自己滚动它。如果有更好的方法,请提供您的答案,我会奖励它。

    import MySQLdb
    import peewee
    from peewee import *
    from datetime import datetime
    
    db = MySQLDatabase('test', user='root',passwd='psswd')
    
    class BaseModel(Model):
        class Meta:
            database = db
    
    class Noteable(BaseModel):
        type = CharField(null = False)
    
    # This will act as the trigger that inserts a row into noteable,
    # and retrieves the notable.id to use
    class N(BaseModel):
        def save(self, *args, **kwargs):
            if not self.id:
                noteable = Noteable(type=self.__class__.__name__.upper())
                noteable.save()
                self.noteable = noteable.id
            return super(N, self).save(*args, **kwargs)
    
    class Subject(N):
        name = CharField(null = False, unique = True)
        noteable = ForeignKeyField(Noteable, related_name="noteablesubject", null= False, unique = True)
    
    
    class Book(N):
        name = CharField(null = False, unique = True)
        subject = ForeignKeyField(Subject, related_name="books", null = False)
        noteable = ForeignKeyField(Noteable, related_name="noteablebook", null= False, unique = True)
    
    
    class Chapter(N):
        name = CharField(null = False)
        chapter_number = IntegerField(null = False)
        book = ForeignKeyField(Book, related_name="chapters")
        noteable = ForeignKeyField(Noteable, related_name="noteablechapter", null= False, unique = True)
    
    
    class Note(BaseModel):
        note = TextField(null = False)
        # N.B. unique is not true, as multiple notes can go to the same subject/book/chapter
        noteable = ForeignKeyField(Noteable, related_name="notes", null= False)
    
    
    Note.drop_table(True)
    Chapter.drop_table(True)
    Book.drop_table(True)
    Subject.drop_table(True)
    Noteable.drop_table(True)
    
    Noteable.create_table(True)
    Subject.create_table(True)
    Book.create_table(True)
    Chapter.create_table(True)
    Note.create_table(True)
    
    s = Subject(name="subject")
    s.save()
    n = Note(note="subject notes", noteable = s.noteable)
    n.save()
    n = Note(note="subject notes 2", noteable = s.noteable)
    n.save()
    b = Book(name="book", subject=s)
    b.save()
    n = Note(note="book notes", noteable = b.noteable)
    n.save()
    n = Note(note="book notes 2", noteable = b.noteable)
    n.save()
    c = Chapter(chapter_number=1, name="chapter", book=b)
    c.save()
    n = Note(note="chapter notes", noteable=c.noteable)
    n.save()
    n = Note(note="chapter notes 2", noteable=c.noteable)
    n.save()
    

    (如果你希望notes和notable之间有多对多的关系,你必须定义一个带有外键的NoteNotable类并从Note中删除FK)

    您可以定义一个辅助方法来左加入任何带注释的类:

    def get_notes(clazz, id):
        return clazz.select().join(Noteable).join(Note, JOIN_LEFT_OUTER).where(clazz.id = id)
    

    你可以像这样迭代它:

    % for note in chapter.noteable.notes:
    
    % end
    

    这是来自SELECT * FROM NOTABLE;的结果

    +----+---------+
    | id | type    |
    +----+---------+
    |  1 | SUBJECT |
    |  2 | BOOK    |
    |  3 | CHAPTER |
    +----+---------+
    

    这是来自SELECT * FROM NOTE;的结果

    +----+-----------------+-------------+
    | id | note            | noteable_id |
    +----+-----------------+-------------+
    |  1 | subject notes   |           1 |
    |  2 | subject notes 2 |           1 |
    |  3 | book notes      |           2 |
    |  4 | book notes 2    |           2 |
    |  5 | chapter notes   |           3 |
    |  6 | chapter notes 2 |           3 |
    +----+-----------------+-------------+
    

    【讨论】:

      猜你喜欢
      • 2021-05-01
      • 2010-09-05
      • 1970-01-01
      • 1970-01-01
      • 2018-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多