2

私は最近 Django を使い始めましたが、まだ python/Django を楽しんでいますが、現在、論理的な問題に苦しんでいます。

状況 (簡略化):

class A(models.Model):
    foo = models.CharField(max_length=255)

class B(models.Model):
    bar = models.CharField(max_length=255)
    foo =  models.ForeignKey(A)

class C(models.Model):
    title = models.CharField(max_length=255)
    bar =  models.ForeignKey(B)

class D(models.Model):
    name = models.CharField(max_length=255)
    title =  models.ForeignKey(C)
    bar =  models.ForeignKey(B)

(実際の使用例は、これらのクラスの数百で構成されています。はい、それは混乱です。これは明らかに悪いデータベース設計を証明していますが、それについては何も変更できません)

すべてのクラスに動的 ModelForms を作成しました。一般的な目的は、Excel ファイルを取得し、フィールド検証などで適切な ModelForms に挿入することです。すべての Excel ファイルには、クラスにマッピングされた複数のシートがあり、最初の行 (ヘッダー) はモデルフィールドを記述し、他のすべての行はデータを表します。

データは完全にソートされていないため、通常、外部キー シーケンスを壊さない挿入順序は A => B => C => D になります。しかし、この場合、シーケンス全体は D => B => C => A のようになります。関連する外部キーがまだ定義されていないために検証されない最初のシート D を検証すると、問題が発生します。

問題は、すべてのデータを追加して、後で参照整合性を検証するにはどうすればよいかということです。

前もって感謝します!


ご協力いただきありがとうございます!

実際には、すべての主キーは、すべての子テーブルのマッピング テーブルを保持するルート モデルから派生します。状況をシンプルにしたかったので、最初の投稿では言及しませんでした。そうは言っても、それを変更することはできません (めちゃくちゃです!) また、既存の (面倒な!) データベースにマップするクラスを再設計することもできません。そして、この混乱を完全にするために、すべてのフィールドが「not Null」に設定されています。

私の 2 番目のアイデアは、最初にマッピング テーブルに入力し (実際の方法はまだわかりません)、これによって受信データを並べ替えることでした。猿の仕事のように聞こえます、それは汚いです、そして私はこの考えが好きではありません.もっと賢い方法があることを望みました.

この問題に対する数学的な解決策について何かヒントはありますか? これは、任意のデータでツリーをスパンするようなものです。

アップデート:

これを解決するために 2 つの関数を作成しましたが、エラー処理はまだテストしていません。

validate_tables: 指定されたアプリに関連するすべてのテーブルを探し、ネストされたリスト (self.found_fields) を dict (子: [親、親、(...)]) に保存します。

gen_sequence: object_names への正しいシーケンス マッピングを使用してリスト (self.sequence) に書き込みます。

承認歓迎!

これが私の現在の解決策です(アイデアを得るためのスニペット)

    def validate_tables(self):
        app = get_app("testdata")
        self.sequence = []
        self.found_fields = {}
        for model in get_models(app):
            hits = []
            for local_field in model._meta.local_fields:
                if isinstance(local_field, models.ForeignKey):
                    hits.append(local_field.related.parent_model._meta.object_name)
            self.found_fields.update({model._meta.object_name: hits})
        if self.gen_sequence():
            return True
        else:
            raise self.sequence_errors


    def gen_sequence(self, unresolved=None):

        if unresolved:
            self.found_fields = unresolved
            unresolved = {}
        else:
            unresolved = {}

        for model in self.found_fields:
            if ((all(parent in self.sequence for parent in self.found_fields[model]) 
                 and self.sequence)
                or not self.found_fields[model]):
                self.sequence.append(model)
            else:
                unresolved.update({model: self.found_fields[model]})

        if unresolved == self.found_fields:
            self.sequence_errors = unresolved
            return False
        elif not unresolved:
            return self.gen_sequence
        else:
            return self.gen_sequence(unresolved)
4

1 に答える 1

0

独自の主キーを定義する必要があります。適切なフィールドがあると仮定します。そうしないと、この問題は発生せず、ForeignKey を null にすることもできます。難しいのは、後で参照整合性を確立することです。これは困難ですが、Djangoでは不可能ではないようです。

代わりに、2 つのフィールド (1 つは仮想主キー) を持ち、現在の外部キーを null 可能にします。

class A(models.Model):
    foo = models.CharField(max_length=255)

class B(models.Model):
    bar = models.CharField(max_length=255)
    foo =  models.ForeignKey(A, null=True)
    foo_key =  models.CharField()

次に、データのインポート後に foo_key を持つすべての「B」オブジェクトを見つけ、関係を確立して foo_key を null に設定します。

これは、以前の GAE プロジェクトから PostgreSQL データベースに大量のデータをインポートするときに使用したメカニズムです。

于 2013-01-15T20:38:36.497 に答える