22

再利用可能なDjangoアプリを作成するために最善を尽くしています。今、私はそれらをすべてまとめて最終的なプロジェクトを作成する方法に戸惑っています。

これが私の言いたいことの例です:私は画像を保存、サイズ変更、表示する画像アプリを持っています。また、テキストを保存、編集、表示するウェブログアプリもあります。次に、これら2つを組み合わせて、ブログの投稿と画像を表示します。

そのために、ブログに外部キーフィールドを配置して写真を指すようにすることができます。しかし、その後、ブログは画像アプリなしでは使用できませんでした。また、両方を接続する3番目のアプリを作成することもできます。

それを行うための「ベストプラクティス」の方法は何ですか?

編集:あなたの非常に良い答えをありがとう、しかし私はまだこの問題を解決する方法のより実際的な例を探しています。私の例を完了するには:画像アプリなしでブログアプリを使用すると便利な場合があります。しかし、依存関係をハードコーディングすると、それは不可能になります。では、3番目のアプリで両方を組み合わせるのはどうですか?

4

4 に答える 4

16

答えの一番下にある紹介の話(答えにもっとまっすぐに)。テキストと呼ばれるテキスト処理用のアプリと画像と呼ばれる画像処理用のアプリが1つと、ブログと呼ばれるブログ用の3番目のアプリがあると仮定します。

大局

Pythonプログラマー向けのテンプレート言語に関するマニュアルを学ぶ必要があります。アイデアは、それぞれが独自のアプリにあり、すべてを接続する3番目のアプリがあるということです。次に、アプリはモデルとビューを好きなように提供し(アプリが何をすべきかに焦点を合わせ続けることを忘れないでください)、一連のテンプレートタグも提供する必要があります。

包含タグの作成方法

インクルージョンタグを作成すると、とても簡単です。通常のビューを作成することを思い出させます。

アプリフォルダにディレクトリtemplatetagsを作成します。また__init__.py、このtemplatetagsにファイルを作成します(ディレクトリがpythonパッケージになります)。

次に、Pythonファイルを作成します。名前は重要です。これは{% load xyz %}、アプリを使用するテンプレートで使用します。たとえば、ファイルを呼び出す場合は、それを使用するすべてのテンプレートをpicturestags.py呼び出します。
{% load picturestags %}

最初にファイルに、あまり考える必要のないいくつかの政治を追加します。他の何よりも先にこれを含めてください。

from django.template import Library
register = Library()

次に、タグと同じ名前の関数を定義して、タグを追加します。例ではこれをdisplay_pictureと呼び、1つの引数urlを取ります。関数は、テンプレートで使用する辞書を作成する必要があります。私の例では、URLが指している画像を表示するだけです。

@register.inclusion_tag('pictures/display_picture.html')
def display_picture(url):
    return {'picture': url}

アプリでパステンプレート/画像を作成し、その中に次のものを含むファイルdisplay_picture.htmlを作成します。

<img src="{{ picture }}" />

ご存知かもしれませんが、@ registerはこれをタグにします。辞書内にあるdisplay_pictureが返すのは、display_picture.htmlで使用できるものです。通常のビュー機能と非常によく似ています。

最終的には、次のファイルになります。

pictures/
    __init__.py
    models.py
    views.py
    tests.py
    templates/
        pictures/
            display_picture.html
    templatetags/
        picturetags.py

Pictureアプリに追加する必要があるのはこれだけです。ブログアプリでこれを使用するには、INSTALLED_APPSに画像を追加する必要があります。次に、テンプレートで、独自の新しくホームベイクされたタグを使用する必要がある場合、最初にそれをロードします。次に、次のよう{% load picturestags %}にタグを追加します。{% display_picture https://www.google.com/intl/sv_ALL/images/logos/images_logo_lg.gif %}

{% load picturestags %}
<html>
    <body>
        {% display_picture https://www.google.com/intl/sv_ALL/images/logos/images_logo_lg.gif %}
    </body>
</html>

結果

これはほんの小さな例ですが、これを拡張するのは非常に簡単であることがわかります。あなたのブログは、モデルをインポートして外部キーを押すことで、TextandPicturesアプリを接続できます。特定のブログ投稿のテキストと画像を接続しています。blog_post.html-templateは次のようになります(簡略化):

{% load picturestags %}
{% load texttags %}
<html>
    <body>
        <h1>{{ subject }}</h1>
        <div class="article">{% article_to_html articleid %}</div>
        <div class="article_picture">{% display_picture %}</div>
    </body>
</html>

ブログだけが依存関係を持っており、それが持つべき依存関係であることに注意してください(テキストと写真のないブログはありません...しかし、写真はテキストなしで生きることができます)。外観と配置は、CSSおよびDIV/SPANタグによって制御する必要があります。このようにして、画像アプリを取得して、テキストアプリについて知らない人に渡して使用し、コードに触れることなく、さまざまな方法で画像を表示できます。

昨日これを学んだばかりなので、インクルージョンタグだけを知っています。生活をシンプルにするためにDjangoが提供する便利さだと思います。ドキュメントページには、さらに多くの情報があります(「実際の」タグを「ショートカット」なしで難しい方法にする方法を含む)。したがって、この方法が制限されていることに気付いた場合は、ドキュメントを読んでください...多くの例があります。また、フィルター、simple_tags、スレッドの考慮事項、およびその他の高度な機能の作成方法についても説明します。

序章

私はあなたと同じようにこの問題を抱えていました、そして私はまた私が読んだ答えとは異なる何かを望んでいました(私は答えが悪いとは言いません、彼らは私に多くを学びそして私に洞察を与えてくれました、しかし私は今書いているこれを望んでいました) 。私はあなたの質問のおかげで、そして間違いなくStack Overflowのおかげで、あまり明白ではない何かを理解することができたので、これはおそらく放棄された半年前の質問への私の貢献です(グーグルを助けるかもしれません)!

また、 Google Tech TalkReusableAppsから多くのインスピレーションを得ました。最後に(43分)、彼はdjango-taggingのようないくつかの良い例に言及します。これは、再利用可能なアプリを作成する方法のモデルであると彼は言います。それは私にこれらすべてのアイデアを与えました、なぜならそれはdjangoタグ付けが私たちが持っていた/持っているこのまさに問題を解決する方法だからです。

これをすべて書いた後(1時間かかりました)、グーグルだけでなく、他の人がしていることをフォローしたり、他の人が私が必要なことを書いていないと不平を言ったりするのではなく、貢献できるかもしれないと初めて感じます。他の人がこれをグーグルできるように、私は初めて自分の意見を書く責任を負っています(この段落を書かなければなりませんでした:-)それは細かく砕かれたり無視され忘れられたりしても本当に素晴らしい気分です)。

于 2013-01-14T22:01:17.153 に答える
6

プロジェクトでサードパーティのアプリを使用するのと同じように考えてください。「再利用可能」とは、「依存関係なし」を意味するものではありません。それどころか、DjangoまたはコアPythonライブラリに依存しているだけの場合でも、少なくとも1つの依存関係を持たないアプリを見つけるのは難しいでしょう。(コアPythonライブラリは通常、「安全な」依存関係と見なされます。つまり、誰もがそれを持っていますが、Pythonのバージョン間で状況が変わることがあるため、アプリを特定の時点にロックし続けます)。

再利用可能の目的はDRYの目的と同じです。つまり、同じコードを何度も書きたくないということです。その結果、他のアプリやプロジェクトで何度も使用できるため、画像アプリのような機能を分割することは理にかなっていますが、画像アプリには依存関係があり、他のパッケージはそれに依存します。循環依存関係はありません。問題ありません(循環依存関係は、実際に機能を分離していないことを意味します)。

于 2012-07-20T15:19:23.717 に答える
5

これは良い質問であり、管理するのも非常に難しいと思います。しかし、これらのアプリケーションが公開されていると思いますか、それとも自分だけで使用していますか?あなたがリリースしていなければ、私はそれについてあまり心配しませ

もう1つは、依存関係は問題ないということです。あなたの例の写真アプリは、「再利用可能な」アプリとして適しているように思えます。シンプルで、1つのことを実行し、他のアプリで使用できます。

一方、ブログアプリは通常、画像アプリやタグ付けアプリなどの他のアプリを使用する必要があります。この依存関係は問題ないと思います。画像アプリによってそこに配置されたメディアリソースにリンクするだけで、少し抽象化することができます。

それはすべてほんの少しの常識です。アプリをスリムにできますか?はいの場合は、再利用できるように作成してみてください。しかし、それらが理にかなっているときに依存関係を取ることを恐れないでください。また、依存関係を他の依存関係と交換できるように、拡張ポイントを許可するようにしてください。ここでは直接外部キーは役に立ちませんが、おそらくシグナルやRestfulAPIのようなものが役立ちます。

于 2012-07-20T12:27:51.723 に答える
4

私はDjangoの初心者ですが、同じ問題に直面しました。Djangoコミュニティで再利用可能なアプリについて多くの話題があるのは恥ずべきことですが、ハードコードされた依存関係なしでプロジェクトでそれらを接続する方法についての単一の信頼できるリファレンスではありません。

私は新しいDjangoプロジェクトに取り組んでおり、ハードコーディングをできるだけ避けるためにモデルをセットアップしたいと思っていました。これが私が使ったパターンです。

レイアウト

project_root/
    core/
        models/
            mixinmodels1.py
            mixinmodels2.py
            ...
        utils.py
        ...
    app1/
        models/
            __init__.py
            base.py
            basemixins.py
            mixins.py
            concrete.py
        /signals
            __init__.py
            handlers.py
        utils.py
        ...
    app2/
        ...
    ...

アプリモデル

base.py:このモジュールは、抽象クラスにそのアプリの「存在理由」のみを実装します。ルールは次のとおりです。

  • このモジュールは通常、アプリからのみインポートしcoreます。通常、同じプロジェクト内の他のアプリからは何もインポートされません。

  • 上記のルールの例外は、「存在理由」が別のアプリの存在を前提としている場合です。たとえば、アプリはどこかgroupにアプリがあることを前提としています。userこの場合、それらをリンクする方法は次のとおりです。

    # project_root/settings.py
    
    AUTH_USER_MODEL = 'app_label.UserModel'
    
    # project_root/groups/models/base.py
    
    from django.conf import settings
    

    次に、settings.AUTH_USER_MODELを使用してuserモデルを参照します

  • このパターンは、アプリだけでなく、すべてのアプリに使用しますuser。たとえば、次のことも行う必要があります

    # project_root/settings.py
    
    GROUP_MODEL = 'app_label.GroupModel'
    
  • 上記のパターンを使用する場合base.pyは、リンク先の他のアプリが提供する機能のみを想定してください。手の込んだ具象クラスの機能を想定しないでください(具象クラスをどこに置くかについては後ほど説明します)

  • もちろん、django、サードパーティのアプリ、Pythonパッケージからのインポートは許可されています。

  • アプリで行う仮定がbase.pyしっかりしていて、将来あまり変わらないことを確認してください。良い例はdjango-registrationJamesBennettによるものです。古いアプリですが、確固たる前提を持っていたため、その魅力は衰えませんでした。優れた再利用可能なアプリは1つのことをうまく行うので、その一連の仮定を見つけることは難しくありません。

basemixins.py:このモジュールは、そのアプリの具体的なモデルへのプラグを実装する必要があります。モデルMへの「プラグ」は、モデルMへの外部キーを含む任意のモデルです。例:

# project_root/groups/models/basemixins.py

from django.conf import settings
from django.db import models

class BaseOwnedByGroup(models.Model):
    """
    This is a plug to the group model. Use this
    to implement ownership like relations with 
    the group model
    """
    owner = models.ForeignKey(settings.GROUP_MODEL,
        related_name = '%(app_label)s_%(class)s_owner',
        verbose_name = 'owner')

    # functionality and manager definitions go here.

    class Meta:
        abstract = True
        app_label = 'groups'

BaseOwnedByGroupgroupモデルへの「プラグ」です。ここでのルールは'base.py`と同じです

  • で「プラグ」を定義するbasemixins.pyときは、によって提供される機能のみを想定してbase.pyください。
  • core、django、サードパーティのアプリ、Pythonパッケージからのみインポートします。

mixins.py:このモジュールは2つの目的に使用する必要があります

  • 精巧な「プラグ」を定義します。これは、精巧な具象クラスの機能を想定していますが、他のアプリとの関係は想定していません。手の込んだプラグは、理想的にはで定義された「ベースプラグ」の1つを継承する必要がありbasemixins.pyます。

  • そのアプリの具象クラスで使用できるミックスインモデル(「プラグ」ではない)を定義します。

concrete.py:このモジュールは、そのアプリの具体的なクラスを定義し(ご想像のとおり)、他のアプリとの関係を設定するために使用する必要があります。つまり、このモジュールは、プロジェクトと、プロジェクトで提供するすべての機能を前提としています。

他のアプリとの関係は、次のように設定する必要があります。

  • アプリのモデルMとの関係を確立するone to oneには、次の手順を実行します。many to oneanother_app

    # project_root/another_app/utils.py
    
    def plug_to_M_factory(version_label):
        """
        This is a factory method which returns
        the plug to model M specified by 
        version_label
        """
        if version_label == 'first_version':
            from another_app.models.basemixins import BasePlugToM
            return BasePlugToM
        if version_label == 'second_version':
            from another_app.models.mixins import PlugToM
            return PlugToM
        ...
    
    # project_root/groups/models/concrete.py
    
    from groups.models.base import BaseGroup
    from another_app.utils import plug_to_M_factory
    
    PlugToMClass = plug_to_M_factory(version_label = 'second_version')
    
    class ConcreteGroup(BaseGroup, PlugToMClass):
        # define your concrete model
    
        class Meta:
            app_label = 'groups'
    
  • 関係を確立するには、モデルmany to manyを使用することをお勧めします。(モデルで行ったのとまったく同じ方法で)モデルのthrough正しいプラグインを継承しますthroughConcreteGroup

signals:関係を設定しているときに、アプリapp1のモデルNがapp2変更されたときに、アプリのモデルMで操作を実行する必要があることがよくあります。シグナルを使用してそれを処理できます。ハンドラーは具体的な送信者の機能を引き受けることができますが、多くの場合、引き受ける必要はありません。の送信者の基本バージョンを想定するbase.pyだけで十分です。settings.ModelNameこれが、具体的なモデルを参照するために常に使用することをお勧めする理由です。次のようにプロジェクト全体の関数をsettings.ModelName使用または使用することにより、文字列からモデルクラスを抽出できます。ContentTypeget_model_for_settings

# project_root/project/utils.py

from django.db.models import get_model
from django.core.exceptions import ImproperlyConfigured

def get_model_from_settings(model_string):
    """
    Takes a string of the form 'app_label.model' as input, returns the 
    appropriate model class if it can find it.
    """
    try:
        app_label, model_name = model_string.split('.')
    except ValueError:
        raise ImproperlyConfigured("function argument must be of the " 
            "form 'app_label.model_name', got '%s'" % model_string)

    model = get_model(app_label, model_name)

    if model is None:
        raise ImproperlyConfigured("function argument refers to model "
            "'%s' that has not been installed" % model_string)

    return model

core:コアアプリは、プロジェクト全体のミックスイン機能を保存する特別なアプリです。

  • これらのミックスインは、他のアプリについて何も想定してはなりません。このルールの唯一の例外は、settings.AUTH_USER_MODELの基本機能に依存するミックスインです。userこれは、ほとんどのプロジェクトにモデルがあると安全に想定できるためです。

  • もちろん、django、サードパーティ、Pythonパッケージからのインポートは引き続き許可されます

  • すべてのモジュールbase.pybasemixins.pyモジュールはからインポートできることに注意してcoreください。

最後に、すべてが意図したとおりに機能するようにmodels/__init__.py、すべてのアプリにモデルをインポートします。

このスキームに従うことで私が見つけた利点は次のとおりです。

  • モデルは再利用可能です。誰でも抽象的なベースモデルとミックスインを使用して、独自の具体的なモデルを設計できます。base.pybasemixins.pyおよび関連するファクトリメソッドは、ベアボーンコンクリートモデルと一緒にバンドルして、再利用可能なアプリで出荷できます。

  • アプリは拡張可能です。すべてのミックスインはバージョン管理されており、明確な継承スキームがあります。

  • アプリは緩く結合されています。外部ミックスインはファクトリメソッドを介してアクセスされ、外部モデルはdjango.conf.settingsを使用して参照されます。

  • アプリは自己完結型です。アプリに変更を加えると、そのアプリとそのアプリのみが破損する可能性があります。他のアプリはほとんど無傷のままです。外部アプリが壊れた場合でも、これが発生する可能性のある場所が明確に示されます。

私はこのスキームを使用して、アプリ間の結合を減らしています。私は経験豊富なDjangoプログラマーではなく、学ぶことがたくさんあるので、フィードバックをいただければ幸いです。

于 2014-09-25T20:46:57.687 に答える