Django ForeignKey 模型表单

Posted

技术标签:

【中文标题】Django ForeignKey 模型表单【英文标题】:Django ForeignKey Model Form 【发布时间】:2019-04-30 01:05:08 【问题描述】:

我是 Django 的新手。我有两个模型,其中一个模型有外键。我在表单中使用模型表单,当我填写表单时,我的外键字段返回 null。我想要的是当我填写表单外键字段时,根据外键指出的填写。

型号:

class customerInfo(models.Model):
customerName = models.CharField(max_length = 50)
customerContent = models.TextField(max_length = 50)
createdDate= models.DateTimeField(auto_now_add = True)

def __str__(self):
    return self.customerName

class productInfo(models.Model):
    username = models.CharField(max_length = 50)
    passwd = models.CharField(max_length = 50)
    destIp = models.CharField(max_length = 50)
    hostname = models.CharField(max_length = 50)
    productName = models.CharField(max_length = 50)
    customer = models.ForeignKey(customerInfo,on_delete = models.CASCADE,null=True)

    def __str__(self):
        return self.productName

表格:

class customerForm(forms.ModelForm):
    class Meta:
        model = customerInfo
        fields = (
                "customerName",
        )

    class addProductForm(forms.ModelForm):
        class Meta:
            model = productInfo
            fields = (
                    "productName",
                    )


    class productInfoForm(forms.ModelForm):
            class Meta:
                    model = productInfo
                    fields = (
                            "username",
                            "passwd",
                            "destIp",
                            "hostname",
                    )

观看次数:

@login_required(login_url = "/")
def addCustomer(request):
    form = customerForm(request.POST or None)
    content = "form" : form,
    if form.is_valid():
        form.save()
        customerName = form.cleaned_data['customerName']
        return redirect("addproduct")

    else:
        return render(request,"addcustomer.html",content)

@login_required(login_url = "/")
def addProduct(request):
    form = addProductForm(request.POST or None)
    content = "form" : form
    if form.is_valid():
        global productName
        productName = form.cleaned_data['productName']
        return redirect("addproductinfo")
    return render(request,"addproduct.html",content)

@login_required(login_url = "/")
def addProductInfo(request):
    form = productInfoForm(request.POST or None)
    content = "form" : form
    if form.is_valid():
        p = form.save(commit = False)
        p.productName = productName
        p.save()
        return redirect("customer")
    return render(request,"addproductinfo.html",content)

结果,我想在点击客户名称时看到客户的产品。不是所有的产品。 在我可以这样做之前,客户 ID 字段需要是完整的。 我希望你能理解我。

【问题讨论】:

【参考方案1】:

您的问题和代码示例不清楚。 首先,您应该将模型分解为几个用例:

客户:客户列表,创建、读取、更新和删除 (CRUD) 客户 产品:产品列表,创建、读取、更新和删除 (CRUD) 产品

您可以从客户列表中读取一个,然后在“显示的详细视图”中创建、更新或删除它。

您可以从产品列表中读取一个,然后在“显示的详细视图”中创建、更新或删除它。

可以通过客户列表上每行显示的额外按钮/链接来完成从客户列表到产品列表的传递,因为您的按钮/链接用于显示任何客户详细信息。

客户 PrimaryKey (PK) 通过 url 定义传递给详细信息。

path('customer/<pk>', views.customer_detail_view, name='customer_detail'),

此网址仅供展示。每个数据库操作还需要一个:创建、更新、删除。在下面为您的客户查找 urls.py 代码示例。产品也需要相同的。

from django.urls import path
from . import views

urlpatterns = urlpatterns + [
    path('customer', views.customer_list_view, name='customer_list'),
    path('customer/add', views.customer_add_view, name='customer_add'),
    path('customer/<pk>', views.customer_detail_view, name='customer_detail'),
    path('customer/<pk>/upd', views.customer_update_view, name='customer_update'),
    path('customer/<pk>/del', views.customer_delete_view, name='customer_delete'),
    ]

请注意,create 不会通过 'pk',因为它还未知...

从列表视图调用详细视图在您的 html 模板中完成

<tbody>
% for i in customer_list %
<tr>
  <td><a href="% url 'customer_detail' pk=i.id %"> i.customerName </a></td>
  <td> i.customerContent|default_if_none:"" </td>
</tr>
% endfor %
</tbody>

参数由 kwargs (dict) 通过 url 传递,如果您使用 ClassBasedView (generic.DetailView),它将自动处理。如果没有,你必须像这样抓住 kwargs:kwargs.get('pk') or kwargs.pop('pk') 最后一个从 kwargs 中删除 'pk'。您也可以使用 args(无 pk 键分配)% url 'customer_detail' i.id % 传递“pk”。这也可以直接在模型的 get_absolute_url 函数中定义。 def get_absolute_url(self): return reverse_lazy('customer_detail', args=[str(self.id)]) 要么 def get_absolute_url(self): return reverse_lazy('customer_detail', kwargs='pk': self.pk)

通过这种方式,您还可以管理您的“productName”全局变量,这是应该避免的!顺便说一句我不明白你为什么愿意将productName和productInfo的创建分开???为什么不把它们放在一起呢?

最后,如果您想为您的产品显示几个可能的编码行,您应该查看Django-FormSet。在 Google 上搜索 FormSet 教程,但这是一个更高级的功能。

具有 5 个可能的编码行的 ProductFormset 如下所示:

from django.forms import modelformset_factory

ProductFormset = modelformset_factory(
    productInfo,
    fields=('productName', ),
    extra=5,
    widgets='name': forms.TextInput(attrs=
            'class': 'form-control',
            'placeholder': 'Enter product Name here'
        )
    
)

【讨论】:

【参考方案2】:

如果你想重用 productInfo 模型,那么你应该使用 models.ManyToManyField 而不是 ForeignKey。正如我所理解的那样,您希望拥有一个可以让多个客户“连接”到的产品,对吧?

了解更多 --> https://docs.djangoproject.com/en/2.1/ref/models/fields/

还有更多 --> https://www.revsys.com/tidbits/tips-using-djangos-manytomanyfield/

我的用法:

class EventVocab(models.Model):
    word              = models.CharField(max_length = 30)
    word_chinese      = models.CharField(max_length = 30,blank=True, null=True)
    explanation       = models.TextField(max_length = 200)
    example           = models.TextField(max_length = 100)
    word_audio        = models.FileField(blank=True, null=True)
    explanation_audio = models.FileField(blank=True, null=True)
    example_audio     = models.FileField(blank=True, null=True)

class UserVocab(models.Model):
    event_vocab  = models.ManyToManyField(EventVocab, related_name='event_vocab')
    current_user = models.ForeignKey(User, related_name="vocab_owner", on_delete=models.CASCADE)

在此示例中,UserVocab(在您的情况下为产品)只能连接到一个用户,但一个用户可以有多个 event_vocabs(产品)

【讨论】:

不,一个客户可以有多个产品,但一个产品必须有一个客户,所以我认为我不需要 ManyToManyField。我只想在单击客户名称时查看客户的产品,但首先填写指向 customerInfo 模型中 ID 的外键字段。现在 customer(ForeignKey) 返回 null。 所以客户应该有 models.ManyToManyField(productInfo) 然后 productInfo 是客户的外键,我将更新我的答案以在我的示例中说明它

以上是关于Django ForeignKey 模型表单的主要内容,如果未能解决你的问题,请参考以下文章

Django ForeignKey 表单字段小部件

具有 ForeignKey 字段的模型的 Django ModelForm 无法正确显示 selectBox

Django 表单不使用 ModelChoiceField 保存 - ForeignKey

添加/更改表单中的ForeignKey字段 - Django admin

django - 具有多个 ForeignKey 的 inlineformset_factory

基于model的form表单