如何将详细视图的pk传递到表单的fk中

时间:2019-05-11 23:41:27

标签: django django-models django-forms django-templates django-views

下午好,我是Django的新手,我不确定该怎么做。我有一个使用以下模型的Django 2.2项目:

class Equipment(models.Model):
    name = models.CharField(
            max_length=15,
            unique=True,
            verbose_name='asset name')
    asset_cat = models.ForeignKey('category',on_delete=models.PROTECT,verbose_name='asset category')
    asset_loc = models.ForeignKey('location',on_delete=models.PROTECT,verbose_name='asset location')
    state = models.ForeignKey('status',on_delete=models.PROTECT,verbose_name='status')

    brand = models.CharField(
            max_length=15,
            unique=False,
            blank=True)

    model = models.CharField(
            max_length=12,
            unique=False,
            blank=True,
            verbose_name='model number')

    def __str__(self):
        return "{}".format(self.name)

    def get_absolute_url(self):
        return reverse('equipment-detail', args=[str(self.id)])

    class Meta:
        ordering = ['asset_cat', 'name']
        verbose_name_plural = 'pieces of equipment'


class Action(models.Model):
    name = models.ForeignKey('equipment',on_delete=models.PROTECT,verbose_name='asset name',blank=False)

    dt = models.DateTimeField(
            auto_now_add=True,
            verbose_name='date and time of incident')

    incident = models.TextField(
            blank=True,
            null=True)

    CHANGE = 'CHANGE'
    SERVICE = 'SERVICE'
    ACTION_CHOICES = (
            (CHANGE, 'CHANGE'),
            (SERVICE, 'SERVICE')
    )

    act = models.TextField(
            blank=True,
            choices=ACTION_CHOICES,
            null=True,
            verbose_name='action taken')

    act_detail = models.TextField(
            verbose_name='action detail',
            blank=False)

    result = models.TextField(
            blank=True,
            null=True)

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('service-detail', args=[str(self.id)])

    class Meta:
        ordering = ['-dt']
        verbose_name_plural = 'service calls'

我有这样的设备详细视图:

class EquipmentDetailView(generic.DetailView):
    model = Equipment
    template_name = 'equipment_detail.html'

    def get_context_data(self, **kwargs):
        context = super(EquipmentDetailView, self).get_context_data(**kwargs)

        return context

详细信息视图有两个按钮:编辑和服务。如果单击“编辑”,我将拥有一个模型表单,该模型表单使我可以成功地编辑“设备”模型的该实例。
但是,当我单击服务按钮时,我的表单出现以创建Action模型的实例,但是当我提交该表单时,它告诉我name_id中的null值违反了not null约束。
看来我的问题是,如何将Equipment.id从“设备详细信息”视图传递到action.form创建表单的action.name并保留服务按钮的概念?

操作表格:

class ServiceForm(forms.ModelForm):

class Meta:
    model = Action
    fields = ['incident', 'act_detail', 'result']

操作(实际上是服务)视图:

class EquipmentServiceView(generic.CreateView):
template_name = 'equipment_service.html'
form_class = ServiceForm
queryset = Action.objects.all()

1 个答案:

答案 0 :(得分:0)

假设您不想采用最简单的解决方案在表单字段中包含name并将url设置为:
/equipment/<id>-设备详细信息视图
/service-服务(或操作)创建视图

有几种传递设备ID的方式:

1)来自网址
我们将更改url以接受equipment_id。这意味着您将拥有网址/service而不是/equipment/<equipment_id>/service
可能是最好的解决方案-您将根据REST体系结构使用URL,并且结构非常清晰。客户端可以从任何地方访问页面(就像从邮件中复制粘贴链接一样),它将起作用。

urls.py:

urlpatterns = [
    path('equipment/<int:pk>', EquipmentDetailView.as_view(), name='equipment-detail'),
    path('equipment/<int:equipment_pk>/service', EquipmentServiceView.as_view(), name='service-create')
]

您的服务按钮应如下所示:<a href="{% url 'service-create' object.pk %}">service</a>

最后是您的看法:

class EquipmentServiceView(CreateView):
    template_name = 'equipment_service.html'
    form_class = ServiceForm
    queryset = Action.objects.all()

    def form_valid(self, form):
        equipment_pk = self.kwargs['equipment_pk']
        equipment = get_object_or_404(Equipment, pk=equipment_pk)
        self.object = form.save(commit=False)
        self.object.name = equipment
        self.object.save()
        return super().form_valid(form)

2)会话数据
如果您想保留服务URL而无需添加equipment_id,则可以将设备ID存储在session数据中(在服务器上)或cookie中(在客户端上)。这不是很好-客户必须在创建EquipmentDetailView之前先进入Service,但这将使您的URL保持完整。

views.py:

class EquipmentDetailView(DetailView):
    model = Equipment
    template_name = 'equipment_detail.html'

    def get(self, request, *args, **kwargs):
        response = super().get(request, *args, **kwargs)
        request.session['last_equipment_pk'] = self.object.pk
        return response


class EquipmentServiceView(CreateView):
    template_name = 'equipment_service.html'
    form_class = ServiceForm
    queryset = Action.objects.all()

    def form_valid(self, form):
        equipment_pk = self.request.session.get('last_equipment_pk')
        equipment = get_object_or_404(Equipment, pk=equipment_pk)
        self.object = form.save(commit=False)
        self.object.name = equipment
        self.object.save()
        return super().form_valid(form)

P.S。:nameForeignField的错误字段名-应该类似于equipment之类。这些标签通常与CharField关联,并且应该是字符串。