在“管理员更改表单”中,如何访问模型的当前实例?

时间:2019-05-22 02:09:34

标签: python django

我正在尝试为想要跟踪销售的发布者创建一个数据管理系统。我有一个用于书店的模型,该模型存储着出版商的书籍,其中包括每个商店的状态字段(来自状态模型)。状态可能是“未设置”,“收到订单”或“回叫”。

除了能够查看当前状态之外,客户还希望能够在检查“管理员更改表格”上的书店数据时查看给定商店的状态更改:状态本身,日期和时间状态更改,进行更改的用户以及有关更改的一些注释。因此,我创建了一个状态更改模型来存储此数据,并添加了一个内联。

在书店的“管理员更改表”中,我禁用了状态字段(以防止用户更改状态而不创建状态更改记录),并添加了“更改状态”链接,该链接将用户带到一个表单,以允许他们创建一个新的状态更改记录。我一直无法解决的问题是:如何访问当前的书店实例,以便可以将商店ID及其当前状态传递到更改状态表单?

我可以获取用户的ID,而该请求没有任何问题。我可以使用self.model.objects.first()获取数据库中第一个书店的ID,但是当“更改状态”链接时,我无法找到一种方法来获取正在查看的书店的ID。单击。

在models.py中:

from django.contrib.auth import get_user_model
from django.db import models
from datetime import datetime


class Status(models.Model):
    DEFAULT_PK = 1
    status_name = models.CharField(max_length=255)


class Bookstore(models.Model):
    store_code = models.CharField(max_length=255)
    store_name = models.CharField(max_length=255)
    address = models.CharField(max_length=255, null=True, blank=True)
    phone_number = models.CharField(max_length=255, null=True, blank=True)
    description = models.CharField(max_length=1024, null=True, blank=True)
    status = models.ForeignKey(Status, on_delete=models.SET_DEFAULT, default=Status.DEFAULT_PK)


class StatusChange(models.Model):
    date_time = models.DateTimeField(default=datetime.now)
    user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
    bookstore = models.ForeignKey(Bookstore, on_delete=models.CASCADE)
    status = models.ForeignKey(Status, on_delete=models.CASCADE)
    notes = models.TextField()

在admin.py中:

from django.contrib import admin
from django.urls import path
from django.shortcuts import render
from django.utils.safestring import mark_safe
from django.forms.models import BaseInlineFormSet
from .models import Status, Bookstore, StatusChange
from .forms import StatusChangeForm


class StatusChangeFormSet(BaseInlineFormSet):
    def get_queryset(self):
        qs = super(StatusChangeFormSet, self).get_queryset()
        return qs[:5]


class StatusChangeInline(admin.TabularInline):
    model = StatusChange
    formset = StatusChangeFormSet
    fields =  ('date_time', 'user', 'status', 'notes')
    readonly_fields = ('date_time', 'user', 'status')
    can_delete = False
    max_num = 0
    ordering = ('-date_time',)


class BookstoreAdmin(admin.ModelAdmin):
    model = Bookstore
    list_display = ('id', 'store_code', 'store_name', 'status')
    list_display_links = ('id', 'store_code', 'store_name')
    ordering = ('id', )
    fields =('store_code', 'store_name', 'address', 'phone_number', 'description', 'status')
    inlines = [StatusChangeInline, ]

    # Disable the status field except if we are creating a new bookstore
    def get_readonly_fields(self, request, obj=None):
        if obj:
            return self.readonly_fields + ('status',)
        return self.readonly_fields

    def get_urls(self):
        urls = super().get_urls()
        my_urls = [path('statuschange/', self.change_store_status, name='statuschange'), ]
        return my_urls + urls

    def change_store_status(self, request):
        if request.method == 'POST':
            pass

        obj = self.model.objects.first()
        store_id = getattr(obj, 'id')
        store_status = getattr(obj, 'status')
        form = StatusChangeForm(
            initial={'user': request.user, 'bookstore': store_id, 'status': store_status}
        )
        payload = {"form": form}
        return render(request, "admin/change_status.html", payload)

admin.site.register(Bookstore, BookstoreAdmin)

这当然会将用户带到允许他们更改数据库中第一个书店的状态的表单!

1 个答案:

答案 0 :(得分:0)

目前,您可以通过书店更改路径,例如:
/admin/<app_name>/bookstore/<pk>/change/
我建议您保留此url配置并为statuschange创建url,如:
/admin/<app_name>/bookstore/<pk>/statuschange/

假设您的StatusChangeForm是:

class StatusChangeForm(forms.ModelForm):
    class Meta:
        model = models.StatusChange
        fields = ['user', 'bookstore', 'status',]

因此,您需要调整get_urls()以接受pk中的bookstore

def get_urls(self):
        urls = super().get_urls()
        my_urls = [path('<int:pk>/statuschange/', self.change_store_status, name='statuschange'), ]
        return my_urls + urls

并修改您的change_store_status()以接收该pk并在获取bookstore实例时使用它:

def change_store_status(self, request, pk):
        obj = self.model.objects.get(pk=pk)

        store_id = getattr(obj, 'id')
        store_status = getattr(obj, 'status')
        form = forms.StatusChangeForm(request.POST or None,
            initial={'user': request.user, 'bookstore': store_id, 'status': store_status}
        )

        if request.method == 'POST':
            if form.is_valid():
                form.save()

        payload = {"form": form}
        return render(request, "admin/change_status.html", payload)

此外,您还必须在书店更改模板中提供pk,以指导用户正确填写表格,例如:
{% url 'admin:statuschange' pk=object.pk %}