2017-10-20 4 views
3

Phoenixでモデルを動的に作成して使用する方法はありますか?クライアントのテーブルに関するメタデータを格納するアプリケーションがあります。フィールド(列名と型)をいくつか設定してから、CSVファイルを解析して保存します。格納されたメタデータから、Ectoを使用してクライアントテーブルを管理し、それに対してクエリを実行できるように、モデルを生成したいと思います。Phoenix Frameworkの動的モデル

私は組み込みのORMとtype()関数を使用して、オンザフライでモデルを構築し、アプリケーション内でマイグレーションやその他のモデルコードを生成しなくても使用できるジャンゴバックグラウンドから来ています。 Pythonで

、私は(約)だろう。それに

class MetaModel(models.Model): 
    table_name = models.CharField(...) 
    model_name = models.CharField(...) 
    field_defs = JSONField(...) 

    def resolve_fields(self): 
     # takes values from `field_defs` and converts them into 
     # django field instances 

    def get_model(self): 
     class Meta: 
      app_label = 'dynamic' 
      db_table = self.table_name 
     fields = self.resolve_fields() 
     attrs = {'__module__': 'dynamic', 'Meta': Meta} 
     attrs.update(fields) 
     model = type(self.model_name, (models.Model,), attrs) 
     return model 

    def create_table(self): 
     with connection.schema_editor() as se: 
      model = self.get_model() 
      se.create_model(model) 

を、私は、データベース内のテーブルを作成し、クライアント供給されたデータで動作するようにORMを活用することができますよ。

私は生のSQLを使ってそれを行うことができ、コマンドとクエリを実行するのにEctoを使用することができますが、SQLの束を書いて維持するのではなく、より体系化してEctoの内部を頼りにしたいと思いますテンプレート。

アドバイス(「いいえ、あなたはできません」)は非常に役に立ちます。ありがとう!

答えて

5

はい、Module.create/3で可能です。いくつかの注意点があります:各モジュールの一意の名前を選択する必要があり、モジュールのコードはVMが再起動されるまでメモリに保存され、この関数を呼び出す回数を制限したい場合があります。

ここでは、基本的な実装方法について説明します。モジュール名、テーブル名、フィールド名と型のペアのリストを渡すことができます。

defmodule A do 
    def go(module, table, fields) do 
    Module.create(module, quote do 
     use MyApp.Web, :model 
     schema unquote(table) do 
     unquote(for {name, type} <- fields do 
      quote do 
      field unquote(name), unquote(type) 
      end 
     end) 
     end 
    end, Macro.Env.location(__ENV__)) 
    end 
end 

A.go MyPost, "posts", [ 
    {:title, :string}, 
    {:content, :string}, 
] 

# MyPost is now just like any other Schema module in Phoenix. 

IO.inspect MyApp.Repo.all(MyPost) 

出力:

[debug] QUERY OK source="posts" db=2.8ms queue=0.1ms 
SELECT p0."id", p0."title", p0."content" FROM "posts" AS p0 [] 
[%MyPost{__meta__: #Ecto.Schema.Metadata<:loaded, "posts">, 
    content: "Hello from Joe", id: 1, title: "Hello"}, 
%MyPost{__meta__: #Ecto.Schema.Metadata<:loaded, "posts">, 
    content: "Hello from Mike", id: 2, title: "Hello"}, 
%MyPost{__meta__: #Ecto.Schema.Metadata<:loaded, "posts">, 
    content: "Hello from Robert", id: 3, title: "Hello"}] 
+0

これは、あなたが与えられたモジュールを再定義については行くだろうか、本当にクールですか? – webdeb

+1

これで、同じ名前/原子でモジュールをオーバーライドできます。 – webdeb

+0

これは優れています!どうもありがとうございました! – vforgione

関連する問題