0

2 つの異なるシステムで使用されるデータベースがあり、その結果、次のように FileField 値の先頭にスラッシュを付ける必要があります。

/dirs/filename.ext

ただし、Django では、FileField の値の先頭にスラッシュを付けることができませんMEDIA_ROOT

したがって、私の疑いは、カスタム ストレージ クラスを作成するか、FileField を何らかの方法でカスタマイズして、読み取り時に先頭のスラッシュが取り除かれ、保存時に復元されるようにする必要があるということです。


なぜ私がこれを行っているのか疑問に思っている人のために: 別のDjangoサーバーにファイルをミラーリングしています。

Django サーバーでは、ファイルはメディア ルートに相対的です。したがって、メディア ルートが/path/to/myapp/mediaであると仮定すると、パスを持つファイルdirs/filename.extは に存在し/path/to/myapp/media/dirs/filename.extます。

一方、他のサーバーにミラーリングされると、それらは webroot に対して相対的に保存されます。したがって、パスはファイルの絶対 URL と同じです (たとえば、ファイルdirs/filename.extは に保存され/path/to/example.com/dirs/filename.ext、 としてアクセスされますhttp://example.com/dirs/filename.ext)。

両方のサーバーが同じデータベースを使用しています。

ある解決策は、他のサーバーでフィールドが使用されているすべての場所にスラッシュを追加していることに気付きましたが、それはさまざまなソースファイルにまたがっていますが、Django ではレコードモデルのおかげで、ファイルだけを変更できるはずmodels.pyです。 Django サイト全体で機能します。


これまでのところ、のカスタムバージョンを作成しようとしましたが、ルックアップと保存をFileField正しく前に追加しました、Django アプリ内で使用すると先頭のスラッシュを削除できません。/


マニュアル用の PDF ファイルを含む Tool というレコードを想像してみてください。Django サーバーでは、次のようにテンプレートに表示されます。

<h1>{{ tool.name }}</h1>
<p>{{ tool.description }}</p>
<p><a href="{{ MEDIA_URL }}{{ tool.file.url }}">Link to Manual</a></p>

一方、他のサーバーでは、次のようになります (これは CF コードです)。

<h1>#GetTool.tool_name#</h1>
<p>#GetTool.tool_description#</p>
<p><a href="#GetTool.tool_file#">Link to Manual</a></p>

2 番目のサーバーの例では、絶対 URL である必要があります。

したがって、明確にするために:

  • 2 番目のサーバーは Django プロジェクトではありません
  • 最初のサーバーよりも 2 番目のサーバーでコードを変更すると、はるかに時間がかかります。
  • したがって、FileField の値は、Django との互換性を保つために絶対 URL である必要がありますが、2 番目のサーバーとの互換性を保つには、先頭にスラッシュを付けて保存する必要があります。
4

4 に答える 4

0

最後に、これを行う方法を考え出しました。トリックは、FileField に加えて FieldFile をサブクラス化することでもありました。

class LeadingSlashFieldFile(files.FieldFile):
    def __init__(self, instance, field, name):
        name = re.sub(r'^/', '', name)
        super(LeadingSlashFieldFile, self).__init__(instance, field, name)

class LeadingSlashFileField(models.FileField):
    attr_class = LeadingSlashFieldFile

    def get_prep_lookup(self, lookup_type, value):
        if hasattr(value, 'name'):
            value = value.name
        if value[0] <> '/':
            value = "/" + value
        return super(LeadingSlashFileField, self).get_prep_lookup(lookup_type, value)

    def get_prep_value(self, value):
        value = super(LeadingSlashFileField, self).get_prep_value(value)
        if value is None:
            return None
        value = unicode(value)
        if value[0] <> '/':
            value = "/" + value
        return value

これはうまくいくようです。

于 2013-10-23T20:04:52.463 に答える
0

カスタムフィールドを作成してみることができます。何かのようなもの:

class MyFileField(models.Field):
    attr_class = MyFieldFile

    def get_directory_name(self):
        return os.path.normpath(force_unicode(datetime.datetime.now().strftime(smart_str(self.upload_to))))

    def get_filename(self, filename):
        return os.path.normpath(self.storage.get_valid_name(os.path.basename(filename)))

    def generate_filename(self, instance, filename):
        return os.path.join(self.get_directory_name(), self.get_filename(filename))

    def get_prep_lookup(self, lookup_type, value):
        if hasattr(value, 'name'):
            value = value.name
        return super(FileField, self).get_prep_lookup(lookup_type, value)

    def get_prep_value(self, value):
        "Returns field's value prepared for saving into a database."
        # Need to convert File objects provided via a form to unicode for database insertion
        if value is None:
            return None
        return unicode(value)

これはデフォルトの django-1.4 コードです。そして、必要に応じてスラッシュを追加するように変更する必要があります

フィールド値にアクセスすると、実際にこのクラスが取得されるため、django.db.models.fields.files.FieldFile もサブクラス化する必要があります (例で MyFieldFile を参照)。そして、このクラスには、保存時にパスを変更する save メソッドがあります。したがって、そのクラスのスラッシュを削除します。

この 2 つのクラスのメソッドはストレージ クラスのメソッドを呼び出すため、別のオプションは代替ストレージを作成することです

from django.core.files.storage import FileSystemStorage

class MyStorage(FileSystemStorage):
    def path(self, name):
        try:
            path = safe_join(self.location, name)
        except ValueError:
            raise SuspiciousOperation("Attempted access to '%s' denied." % name)
        return os.path.normpath(path)

    def _save(self, name, content):
        full_path = self.path(name)
        # many lines of code
        return name  # this is used as filename in database

django 設定でデフォルトのストレージを構成します。

DEFAULT_FILE_STORAGE = 'yourapp.import.path.MyStorage'
于 2013-04-02T07:26:58.203 に答える
0

私があなたを正しく理解していれば、特別なフィールドを実行する代わりに、フィールドのスラッシュを追加または削除するメソッドを実行できないのはなぜですか?

少しハックですが、うまくいくと思います。

class MyModelWithAppendingSlash(models.Model):
    my_file = FileField(options_go_here)

    def my_file_appended(self):
        return path = '/' + self.my_file.filename

    def my_file_slash_removed(self):
        return my_file.filename[1:]

次に、djangoアプリでモデルを参照するときに、myModelWithAppendingSlashInstance.my_file_appended()または.my_file_slash_removed()

多くのコードを切り取ったので、変更する必要がありますが、ここで達成しようとしていることの要点を理解できます。これはあなたにとって完全に間違っているかもしれませんが、これが私があなたの質問を解釈する方法です。

于 2013-04-08T12:21:42.567 に答える
0

コード行がなくても、データベースの VIEW を使用してこれを修正できます。'/' (http://example.com/絶対 URL にしたい場合は ' ') とパスを連結するビューを作成するだけです。

CREATE VIEW CF_appname_tool AS
SELECT [other attributes], '/' + file as file
FROM appname_tool;

文字列連結演算子は DBMS ごとに異なるため、SQL サーバーを使用していることを知る必要がありました。

CF コードを CF_appname_tool から選択するように変更するのは面倒だと思います。データを appname_tool からDjango ツール モデルに移動し、 db_tablesome_other_nameオプションを設定できます。

class Tool(model.Model):
    class Meta:
        db_table = 'some_other_name'

appname_toolからの選択としてビューを作成しますsome_other_name

CREATE VIEW appname_tool AS
SELECT [other attributes], '/' + file as file
FROM some_other_name;

実稼働環境でプログラムによって VIEW を作成する場合は、 post_syncdbシグナルをリッスンできます。

于 2013-04-08T18:00:49.820 に答える