1

別の ModelAdmin から 1 つの ModelAdmin メンバー変数を変更する方法が必要です。それで、グローバル変数を使用できるかもしれません。ただし、複数のユーザーが同時にアプリを使用している場合、グローバル変数が予期せず変更され続け、すべての地獄が解き放たれます。

Django に、ある ModelAdmin メンバー変数を別の ModelAdmin から変更できる方法はありますか?

それとも設計ミスですか?私はこれを実際よりも難しくしていますか、それとも何か不足していますか? スレッド化とロックの使用についてはどうですか? メッセージの受け渡し??? イベント?!?!?! ヘルプ


これが全体の話です。私のアプリでは、互換性のある CPU、マザーボード、メモリ、およびハード ドライブを (この順序で) 選択することで、ユーザーが PC を構築できます。CPU を選択することで、CPU のソケットを備えたマザーボードに限定されます。DDR3 調光機能を備えたマザーボードを選択すると、DDR3 メモリに制限されます。

また、システムごとに同じ部品が多数存在する可能性があることを認識してください (例: メモリ モジュールですが、それらは同一である必要がありますcount) through。これには、InlineAdmin モデルを使用して管理ページにフィールドを表示する必要があります。

嬉しいことに、raw_id_field 変数により、ドロップダウン ウィジェットが、change_list.html と同じフォームをポップアップ表示するボタンに置​​き換えられ、ユーザーが必要な部分をフィルター/並べ替え/検索できるようになりました。しかし、これは私の上司にとって十分ではありませんでした。ここで、以前の選択に従ってこれらのフィルターを事前定義する必要があります (つまり、DDR3 を搭載したマザーボードを選択した後、DDR3 を搭載したメモリのフィルター)。だから私はこれを実装しました:Django管理者のデフォルトフィルターですが、他の選択に基づいて動的にCpuAdmin.default_filters設定する方法が必要です。PcAdmin

簡潔にするために一部のモデルのみを含む私のモデル:

# models.py
class CPU(Part):
    partNum = models.CharField(max_length=60)
    price = models.DecimalField(precision=2)
    socket = models.CharField(max_length=60)
    numCores = models.CharField(max_length=60)

class PC(models.Model):
    name = models.CharField(max_length=60)
    customer = models.CharField(max_length=60)
    cpuChoices = models.ManyToManyField(CPU, through='PcCpuChoice')
    memoryChoices = models.ManyToManyField(Memory, through='PcMemoryChoice')
    hardDriveChoices = models.ManyToManyField(HardDrive, through='PcHardDriveChoice')
    motherBoardChoices = models.ManyToManyField(MotherBoard, through='PcMotherboardChoice')

class PcCpuChoice(models.Model):
    pc = models.ForeignKey(PC, unique=False)
    cpu = models.ForeignKey(CPU, unique=False)
    count = models.IntegerField()

# admin.py
class PartAdmin(admin.ModelAdmin):
    class Meta:
        abstract = True
    search_fields = ['partNum', 'description', 'model']
    default_filter = []

    def changelist_view(self, request, extra_context=None):
        if not request.GET.has_key(self.default_filter[0]):
            q = request.GET.copy()
            q[self.default_filter[0]] = self.default_filter[1]
            request.GET = q
            request.META['QUERY_STRING'] = request.GET.urlencode()
        return super(PartAdmin,self).changelist_view(request, extra_context=extra_context)

class CpuAdmin(PartAdmin):
    list_filter = ['brand', 'socket', 'numCores', 'graphics']
    list_display = ('partNum', 'description', 'brand', 'model', 'markupPrice', 'clockSpeed', 'watts', 'voltage')
    default_filter = ['numCores','8'] # need to change this from PcAdmin!!!

class PcCpuInline(admin.TabularInline):
    model = PcCpuChoice
    extra = 1
    max_num = 1
    raw_id_fields = ['cpu']

class PcAdmin(admin.ModelAdmin):
    inlines = [PcCpuInline, PcMotherboardInline, PcMemoryInline, PcHardDriveInline]

admin.site.register(PC, PcAdmin)
4

2 に答える 2

1

これは答えではなく、正しい方向への微調整です。

との変数コンテキストが他にもありlocalますglobal。あなたの場合、コンテキストはuserまたはおそらくですbuild(ユーザーが複数のビルドを同時に実行している場合)。

changelist_view()このメソッドはrequestオブジェクトを取ることに注意してください。これからuser、 、session(任意の量のものがぶら下がっています)、およびその他すべての良好な状態の情報を取得できます。

もう 1 つの観察: マルチスレッド、マルチプロセスの Web 環境では、あなたがそれについて考えるのに慣れているという意味で、実際には「グローバル」はありません。そのような環境で「グローバル」を作成することは可能memcachedですが (たとえば、 を使用)、かなりの作業が必要になります。

于 2012-12-21T16:10:56.843 に答える
0

正しい方向に向けてくれてありがとう@PeterRowell。私はdjangoセッションを使用してフィルターを保存し、javascriptを使用してサーバーにリクエストを送信し、フォームをロードするときにフィルターを更新し、フォームを離れるときにフィルターを削除し、それらのリクエストを処理するビュー関数をいくつか使用し、モデルに関数を追加しました(リクエストをパラメーターとして) 既に保存されている部分ごとにフィルターを更新しchangelist_view、PartAdmin の機能をオーバーライドして、request.session のフィルターを使用してクエリ文字列を変更します。これは多くの異なるファイルの多くのコードでしたが、次のような解決策を探している人に役立つことを願ってハイライトをいくつか示します。

質問に投稿されたすべてのモデルはほとんど同じままでした。

PC のビュー:

def update_filters(request):
    try:
        # get POST data
        url = request.POST['form_url']
        id = url.split('/')[-2:-1][0]
        system_type = url.split('/')[-3:-2][0]

        if id is not "new":
            system_content_type = ContentType.objects.get(app_label="systems", model=system_type.rstrip('s'))
            system = system_content_type.get_object_for_this_type(id=id)
            system.set_filters(request)
        else:
            request.session['filters'] = ''
        return HttpResponse("Filters where updated.")
    except:
        return HttpResponse("Select a part and click 'Save and continue' to set the filters.")


def delete_filters(request):
    request.session['filters'] = ''
    return HttpResponse("Filters where deleted.")

これは、change_form.html に配置された JavaScript です (PcAdmin の add_view および change_view 関数の extra_context パラメータを介して追加されました)。

    function post_to_url(path, params, method) {
        method = method || "post"; // Set method to post by default, if not specified.

        // The rest of this code assumes you are not using a library.
        // It can be made less wordy if you use one.
        var form = document.createElement("form");
        form.setAttribute("method", method);
        form.setAttribute("action", path);

        for(var key in params) {
            if(params.hasOwnProperty(key)) {
                var hiddenField = document.createElement("input");
                hiddenField.setAttribute("type", "hidden");
                hiddenField.setAttribute("name", key);
                hiddenField.setAttribute("value", params[key]);

                form.appendChild(hiddenField);
             }
        }

        var frame = document.createElement("iframe");
        frame.name="hidden-form";
        form.target="hidden-form";
        document.body.appendChild(form);
        document.body.appendChild(frame);
        form.submit();
    }

    // when they load the page, set the filters
    $(document).ready(function(){
        post_to_url("/quotegenerator/systems/update_filters/",{'form_url': document.URL});
    });

    // when they exit, delete the filter cookie
    window.onbeforeunload = function() {
        post_to_url("/quotegenerator/systems/delete_filters/", {});
    }

最後に、PartAdmin に追加された機能:

    def set_filters(self, request):
            # query and get the parts
            try:
                    cpu = self.cpuChoices.get()
            except:
                    cpu = False
            try:
                    mobo = self.motherBoardChoices.get()
            except:
                    mobo = False
            try:
                    mem = self.memoryChoices.get()
            except:
                    mem = False
            try:
                    hdd = self.hardDriveChoices.get()
            except:
                    hdd = False

           # for each combo of parts, figure out whats required
            # no parts at all
            if not (mobo or cpu or mem or hdd):
                    request.session['filters'] = ''
            # mobo only
            elif mobo and not (cpu or mem or hdd):
                    request.session['filters'] = 'socket='+mobo.socket
            # cpu only
            elif cpu and not (mobo or mem or hdd):
                    request.session['filters'] = 'socket='+cpu.socket
            # memory only
            elif mem and not (mobo or cpu or hdd):
                    request.session['filters'] = 'memType='+mem.memType
            # hard drive only
            elif hdd and not (mobo or cpu or mem):
                    request.session['filters'] = 'interface='+hdd.interface
            # mobo and cpu
            elif mobo and cpu and not (mem or hdd):
                    request.session['filters'] = 'memType='+mobo.memType+'&interface='+mobo.interface
            # mobo and memory
            elif mobo and mem and not (cpu or hdd):
                    request.session['filters'] = 'socket='+mobo.socket+'&interface='+mobo.interface
            # mobo and hd
            elif mobo and hdd and not (cpu or mem):
                    request.session['filters'] = 'socket='+mobo.socket+'&memType='+mobo.memType
            # cpu and mem
            elif cpu and mem and not (mobo or hdd):
                    request.session['filters'] = 'socket='+cpu.socket+'&memType='+mem.memType
            # cpu and hd
            elif cpu and hdd and not (mobo or mem):
                    request.session['filters'] = 'socket='+cpu.socket+'&interface='+hdd.interface
            # memory and hd
            elif mem and hdd and not (mobo or cpu):
                    request.session['filters'] = 'memType='+mem.memType+'&interface='+hdd.interface
            # mobo cpu and mem
            elif cpu and mobo and mem and not hdd:
                    request.session['filters'] = 'interface='+mobo.interface
            # mobo cpu and hd
            elif mobo and cpu and hdd and not mem:
                    request.session['filters'] = 'memType='+mobo.memType
            # mobo hd and mem
            elif mobo and mem and hdd and not cpu:
                    request.session['filters'] = 'socket='+mobo.socket
            # cpu mem and hd
            elif cpu and mem and hdd and not mobo:
                    request.session['filters'] = 'socket='+cpu.socket+'&memType='+mem.memType+'&interface='+hdd.interface
            # all parts
            else:
                    request.session['filters'] = ''

ああ、PartAdmin の changelist_view 関数は少し変更されました。

def changelist_view(self, request, extra_context=None):
    if ('filters' in request.session):
        q = request.GET.copy()
        for filter in request.session['filters'].split('&'):
            key, value = urllib.splitvalue(filter)
            # check if the request does not already use the filter
            # and that the model has the attribute to filter for
            if (not request.REQUEST.has_key(key)) and (key in self.list_filter):
                q[key] = value
        request.GET = q
        request.META['QUERY_STRING'] = request.GET.urlencode()
    return super(PartAdmin,self).changelist_view(request, extra_context=extra_context)
于 2013-01-10T15:34:31.707 に答える