1

Django モデルを使用して、多数の非正規化テーブルから情報を抽出しようとしています。テーブルは既存のものであり、レガシー MySQL データベースの一部です。

スキーマの説明

各テーブルが人物の特徴を記述し、各人物に名前があるとします (これは本質的に人物を識別しますが、統一された「人物」テーブルには対応しません)。例えば:

class JobInfo(models.Model):
    name = models.CharField(primary_key=True, db_column='name')
    startdate = models.DateField(db_column='startdate')
    ...

class Hobbies(models.Model):
    name = models.CharField(primary_key=True, db_column='name')
    exercise = models.CharField(db_column='exercise')
    ...

class Clothing(model.Model):
    name = models.CharField(primary_key=True, db_column='name')
    shoes = models.CharField(db_column='shoes')
    ...

# Twenty more classes exist, all of the same format

SQL 経由でアクセスする

生の SQL では、すべてのテーブルの情報にアクセスしたい場合、一連の醜いs を実行し、句OUTER JOINでそれを洗練します。WHERE

SELECT JobInfo.startdate, JobInfo.employer, JobInfo.salary,
       Hobbies.exercise, Hobbies.fun,
       Clothing.shoes, Clothing.shirt, Clothing,pants
       ...
FROM JobInfo
     LEFT OUTER JOIN Hobbies ON Hobbies.name = JobInfo.name
     LEFT OUTER JOIN Clothing ON Clothing.name = JobInfo.name
     ...
WHERE
     Clothing.shoes REXEGP "Nike" AND
     Hobbies.exercise REGEXP "out"
     ...;

モデルベースのアプローチ

これを Django ベースのアプローチに変換しようとしています。このアプローチでは、QuerySetすべてのテーブルから情報を引き出すことが簡単にできます。

OneToOneField( example )を使用して、1つのテーブルに他のテーブルと関連付けるためのフィールドを作成することを検討しました。ただし、これは、1 つのテーブルが「中央」テーブルを必要とし、他のすべてのテーブルが逆方向に参照することを意味します。これは 20 数個のフィールドでごちゃごちゃしているように見え、実際には回路図の意味がありません (「ジョブ情報」はコア プロパティですか? 服ですか?)。

私はこれについて間違った方法で進んでいるように感じます。QuerySet各テーブルにすべてのテーブルに共通の 1 つの主キー フィールドがある場合、関連するテーブルに を構築するにはどうすればよいですか?

4

1 に答える 1

2

DBアクセスがこれを許可する場合、おそらくモデルを定義してこれを行い、 DB列をそのモデルへの外部キーとしてPerson宣言し、人物モデルの名前として設定します。その後、クエリで通常の構文を使用できます。nameto_field__

とにかく、 Django が のForeignKeyフィールドについて文句を言わないと仮定します。primary_key=True

class Person(models.Model):
    name = models.CharField(primary_key=True, max_length=...)

class JobInfo(models.Model):
    person = models.ForeignKey(Person, primary_key=True, db_column='name', to_field='name')
    startdate = models.DateField(db_column='startdate')
    ...

to_fieldが主キーとして宣言されている限り、実際には必要ないと思いますがname、わかりやすくするためには良いと思います。nameまたは、直接 PK として宣言しない場合。

ただし、これはテストしていません。

ビューを使用するには、2 つのオプションがあります。どちらも、既知のすべてのユーザー名を含む実際のテーブルで最もうまくいくと思います。おそらく、Django が通常期待するように、数値の PK を使用することもできます。table が存在すると仮定しましょう - それを と呼びますperson

1 つのオプションは、ユーザーに関するすべての情報を網羅する 1 つの大きなビューを作成することです。これは、上記で使用した大きな結合に似ています。

create or replace view person_info as 
    select person.id, person.name,
           jobinfo.startdate, jobinfo.employer, jobinfo.salary,
           hobbies.exercise, hobbies.fun,
           clothing.shoes, ...
    from person
         left outer join hobbies on hobbies.name = person.name
         left outer join jobinfo on jobinfo.name = person.name
         left outer join clothing on clothing.name = person.name
;

少しデバッグが必要かもしれませんが、アイデアは明確です。

db_table = person_info次に、とmanaged = Falseでモデルを宣言しますMeta class

2 番目のオプションは、名前に一致する値を含む各補助テーブルのビューを宣言し、person_idDjango FK を使用することです。

create or replace view jobinfo_by_person as
    select person.id as person_id, jobinfo.*
    from person inner join jobinfo on jobinfo.name = person.name;
create or replace view hobbies_by_person as
    select person.id as person_id, hobbies.*
    from person inner join hobbies on hobbies.name = person.name;

繰り返しますが、.* 構文が機能するかどうかは完全にはわかりません。そうでない場合は、関心のあるすべてのフィールドをリストする必要があります。そして、補助テーブルの列名を確認してください。

次に、モデルをby_personバージョンに向けて、標準の FK セットアップを使用します。

これは少し洗練されておらず、パフォーマンスが良いと主張するつもりはありませんが、データベースをさらに非正規化することを避けることができます。

于 2013-07-11T22:39:08.230 に答える