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 模型表单的主要内容,如果未能解决你的问题,请参考以下文章