SQL Alchemy - предотвращение рекурсии в отношениях один-ко-многим - PullRequest
0 голосов
/ 02 марта 2019

Я заранее прошу прощения за отсутствие объяснения, а также за длину этого поста.Я думаю, что проблема намного проще, чем я ее представляю.У меня есть две модели, использующие отношения один ко многим.Для моего InsightModel у меня есть метод json (), отображающий следующее:

{
    name: "insightname",
    start: 1,
    end: 3,
    podcast_id: 1,
    podcast: {
        name: "podcast1",
        wave_data: 1,
        length: 2,
        host: "Hosterman",
        category: "entertain",
        pub_date: "11/1",
        cover_art_url: "google.com"
    }
}

А для моего PodcastModel метод json () отображает следующее:

{
    name: "podcast1",
    wave_data: 1,
    length: 2,
    host: "Hosterman",
    category: "entertain",
    pub_date: "11/1",
    cover_art_url: "google.com",
    insights: [
        {
            name: "insightname",
            start: 1,
            end: 3,
            podcast_id: 1
        }
    ]
}

Это работает какМне это нужно, но чтобы заставить его работать, мне нужно было создать два метода json () для каждого класса, чтобы избежать рекурсии в PodcastModel, которая бы выглядела следующим образом:

{
    name: "podcast1",
    wave_data: 1,
    length: 2,
    host: "Hosterman",
    category: "entertain",
    pub_date: "11/1",
    cover_art_url: "google.com",
    insights: [
        {
            name: "insightname",
            start: 1,
            end: 3,
            podcast_id: 1,
            podcast: {
                name: "podcast1",
                wave_data: 1,
                length: 2,
                host: "Hosterman",
                category: "entertain",
                pub_date: "11/1",
                cover_art_url: "google.com",
            }
        }
    ]
}

Мой код для PodcastModel:

from db import db
from datetime import datetime

class PodcastModel(db.Model):

    __tablename__ = 'podcasts'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100))
    wave_data = db.Column(db.Float(precision=2))
    length = db.Column(db.Float(precision=2))
    host = db.Column(db.String(80))
    category = db.Column(db.String(80))
    pub_date = db.Column(db.String(50))
    cover_art_url = db.Column(db.String(200)) 

    insights = db.relationship('InsightModel', backref='podcast', lazy='dynamic')

    def __init__(self, name, wave_data, length, host, category, pub_date, cover_art_url):
        self.name = name
        self.wave_data = wave_data
        self.length = length
        self.host = host
        self.category = category
        self.pub_date = pub_date
        self.cover_art_url = cover_art_url

    def json(self):
        return {'name': self.name, 'wave_data': self.wave_data, 'length': self.length, 'host': self.host, 'category': self.category, 'pub_date': self.pub_date, 'cover_art_url': self.cover_art_url, 'insights': [insight.json_no_podcast() for insight in self.insights.all()]}

    def json_no_insight(self):
        return {'name': self.name, 'wave_data': self.wave_data, 'length': self.length, 'host': self.host, 'category': self.category, 'pub_date': self.pub_date, 'cover_art_url': self.cover_art_url}

    @classmethod
    def find_by_name(cls, name):
        # Select * FROM items WHERE name=name LIMIT 1
        return cls.query.filter_by(name=name).first()

    @classmethod
    def find_by_id(cls, _id):
        return cls.query.filter_by(id=_id)

И InsightModel выглядит следующим образом:

from db import db
from models.podcast import PodcastModel

class InsightModel(db.Model):

    __tablename__ = 'insights'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100))
    start = db.Column(db.Float(precision=2))
    end = db.Column(db.Float(precision=2))

    podcast_id = db.Column(db.Integer, db.ForeignKey('podcasts.id'))
    #podcast = db.relationship('PodcastModel')

    def __init__(self, name, start, end, podcast_id):
        self.name = name
        self.start = start
        self.end = end
        self.podcast_id = podcast_id

    def json(self):
        podcast = PodcastModel.find_by_id(self.podcast_id).first().json_no_insight()
        return {'name': self.name, 'start': self.start, 'end': self.end,
                'podcast_id': self.podcast_id, 'podcast': podcast}

    def json_no_podcast(self):
        return {'name': self.name, 'start': self.start, 'end': self.end,
                'podcast_id': self.podcast_id}

    @classmethod
    def find_by_name(cls, name):
        # Select * FROM items WHERE name=name LIMIT 1
        return cls.query.filter_by(name=name).first()

Как вы видите, я добавил методы json_no_insights () и json_no_podcast (), чтобы предотвратитьрекурсия из случившегося.Тем не менее, я уверен, что чтение этого кода уже дало вам чувство безнадежности в желудке, и я отчаянно нуждаюсь в лучшем способе его написать.Большое спасибо за понимание и еще раз, я прошу прощения за длину этого поста или отсутствие объяснения.

1 Ответ

0 голосов
/ 02 марта 2019

Сделайте свою жизнь проще - используйте зефир.

from marshmallow import Schema, fields
from flask import jsonify

class PodcastSchema(Schema):
    name = fields.Str()
    wave_data = fields.Float()
    length = fields.Float()
    host = fields.Str()
    category = fields.Str()
    pub_date = fields.Str()
    cover_art_url = fields.Str()
    insights = fields.Nested('InsightSchema')


class InsightSchema(Schema):
    name = fields.Str()
    start = fields.Float()
    end = fields.Float()
    podcast_id = fields.Integer()

Затем просто сбросьте ваши данные следующим образом:

podcast_schema = PodcastSchema()  # for dict (single)
podcasts_schema = PodcastSchema(many=True)  # for list (array)
jsonify(podcast_schema.dumps(your_json)

Обратите внимание на отсутствие поля podcast в PodcastSchema- это вызвало бы (без настройки) бесконечную рекурсию.Если вам нужно это поле, вы можете попробовать сделать следующее:

class PodcastSchema(Schema):
        name = fields.Str()
        wave_data = fields.Float()
        length = fields.Float()
        host = fields.Str()
        category = fields.Str()
        pub_date = fields.Str()
        cover_art_url = fields.Str()
        # dump insights without podcast field
        insights = fields.Nested('InsightSchema', exclude=('podcast', ))

class InsightSchema(Schema):
        name = fields.Str()
        start = fields.Float()
        end = fields.Float()
        podcast = fields.Nested('PodcastSchema')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...