2016-09-24 14 views
0

部屋予約システムを考えてみましょう。あなたは、Building、Floor、Roomのモデルと予約を持っているかもしれません。私たちは、その建物や床に基づいて部屋に名前を付ける:Djangoが関連商品間でアノテーションを共有する

class Room(models.Model): 
    number = models.PositiveIntegerField() 
    name = models.CharField(..) 
    floor = models.ForeignKey('Floor') 

    def __str__(self): 
     return '%s, #%d Floor %d, %s' % (
      self.name, 
      self.number, 
      self.floor.number, 
      self.floor.building.name 
     ) 

あなたがそれらの何百(例えば管理者リスト、大きなレポートなど)をやっているので、私は執筆に撮影したとき、これははなはだ非効率的ですこのような管理者:

class RoomManager(models.Manager): 
    def get_queryset(self): 
     return super().get_queryset().annotate(
      roomname=Concat(
       'name', 
       V(', #'), 
       'number' 
       V(' Floor '), 
       'floor__number' 
       V(', '), 
       'floor__building__name', 
       output_field=models.CharField() 
      ), 
     ) 

これは機能します。私はそれが欲しかったすべてをやります。高速ですし、を実行するように__str__を修正してから、恐ろしいマルチクエリ文字列ビルダーを実行します。

今のところ私は予約をしています。各予約インスタンスは1つの部屋にリンクされています。 Bookingsをリストするケースは多くありますが、実際に部屋の名前も記載しています。

class RoomManager(models.Manager): 
    def get_queryset(self): 
     return super().get_queryset().annotate(
      roomname=Concat(
       'room__name', 
       V(', #'), 
       'room__number' 
       V(' Floor '), 
       'room__floor__number' 
       V(', '), 
       'room__floor__building__name', 
       output_field=models.CharField() 
      ), 
     ) 

しかし、どのような地獄:私は何をやったか

はBookingManagerを書くのですか?私は自分自身を繰り返している。 DjangoはDRYに関するもので、ここで私は厄介なアノテーションをコピーして貼り付けています。嫌な感じです。

私の質問は...別の方法がありますか?

+0

これは、ビューをモデルに強制的に挿入しようとしているようです。インスタンスの完全な「ブレッドクラム」を返すメソッドが必要な場合は、そのモデルを追加するメソッドその親のブレッドクラム上の名前 - それは基本クラスに再帰します - なぜクエリーセット注釈を使用していますか? – MarZab

+0

実際にクエリセットを編集する必要がある場合は、このメソッドを使用して注釈を作成することもできます。 – MarZab

+0

ルーム名がどこでも使用されている場合は、単にdbカラムとして追加するだけです。床/建物/部屋番号の組み合わせは、これまでになく頻繁に変更されるようなものではありません。 – serg

答えて

0

これを書いている間、私はアイデアがありましたが、私は部屋への関係のために接頭辞を渡すことができる方法を書くことができました。

class RoomManager(models.Manager): 
    def get_queryset(self): 
     return super().get_queryset().annotate(
      roomname=RoomManager.roomname() 
     ) 

    @staticmethod 
    def roomname(prefix=''): 
     return Concat(
      prefix + 'name', 
      V(', #'), 
      prefix + 'number' 
      V(' Floor '), 
      prefix + 'floor__number' 
      V(', '), 
      prefix + 'floor__building__name', 
      output_field=models.CharField() 
     ) 

そしてBookingManagerに、私はちょうどそれはきれいだRoomManager.roomname('room__')

に注釈を付けることができ、私は使用します:私は部屋に関連したものからそれを呼び出すことができますし、それが正しいものになるだろうその方法それ以外の場所ではそれほど賢い気がしません。

0

どうやってこのようにしますか?

+0

私はちょうど質問のコメントでこれを対処したと思うが、具体的には、完全なスペースアドレスがほしいと思う、私はちょうど2つの場所(スペースのquerysetと予約のqueryset)からそれを欲しいので、結合、または数十万(真剣に)の再帰的な照会が含まれます。注釈は私が使用するのが正しいと確信している、問題はモデル間でこの注釈を共有することです。 – Oli

+0

ああ、はい、私は今理解しています。あなたのマネージャはそれを再利用する良い方法ですが、パフォーマンスに関しては@sergには良い点があります - データをキャッシュする作業はデータベースを作業よりもはるかに優れています(キャッシュを無効にする必要がありますが、ディスクスペースは処理能力よりも安いです。 – MarZab

関連する問題