Reputation: 79
I'm newbie on Django. I have two model and one of this model have Foreign Key. I'm using Model Form in forms and when I fill the form my foreign key field return null. What I want is when I fill the form foreign key field, fill according to the pointed out by the foreign key.
Models:
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
Forms:
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",
)
Views:
@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)
As a result, I want to see the customer's products when I click on the customer name. Not all products. Before I can do that, the customer id fields needs to be full. I hope you understood me.
Upvotes: 2
Views: 1153
Reputation: 691
Your question and code sample is not clear. First of all you should break down your model into several use cases:
From the list of customers you can Read one and on the 'detail view displayed' you can Create, Update or Delete it.
From the list of products you can Read one and on the 'detail view displayed' you can Create, Update or Delete it.
Passing from the list of customer to the list of product can be done via an extra Button/Link displayed per line on your Customer List, so as your Button/Link used to display any Customer Detail.
The customer PrimaryKey (PK) is passed to the detail via the url definition.
path('customer/<pk>', views.customer_detail_view, name='customer_detail'),
This url is only for display. You're also need one for each DB operation: Create, Update, Delete. Find below urls.py code example for your customer. You'll need the same for the products.
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'),
]
Note that create doesn't pass 'pk' since it is unknown yet...
The call to the Detail View from the List View is done in your html template
<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>
The argument is passed by kwargs (dict) via the url and if you use ClassBasedView (generic.DetailView) it will be handled automatically. If not, you have to grab the kwargs like: kwargs.get('pk') or kwargs.pop('pk')
the last one remove 'pk' from the kwargs. You could also pass the 'pk' using args (no pk key assignement) {% url 'customer_detail' i.id %}
. This can also be defined directly in a get_absolute_url function of your model.
def get_absolute_url(self):
return reverse_lazy('customer_detail', args=[str(self.id)])
or
def get_absolute_url(self):
return reverse_lazy('customer_detail', kwargs={'pk': self.pk})
By doing that way you'll also be able to manage your 'productName' global variable, which should be avoided! By the way I don't understand why you're willing to separate the creation of productName and productInfo??? Why not keeping them all together?
Finally, if you want to display several possible encoding line for your Product, you should take a look at Django-FormSet. Search google for FormSet Tutorial but this is more an advanced feature.
A ProductFormset with 5 possible encoding lines would look like:
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'
})
}
)
Upvotes: 2
Reputation: 119
If you want to reuse the productInfo model then you shoud you models.ManyToManyField instead of the ForeignKey. As i understand correctly you want to have a product that multiple of the customers can "connect" to , right ?
for more --> https://docs.djangoproject.com/en/2.1/ref/models/fields/
and more --> https://www.revsys.com/tidbits/tips-using-djangos-manytomanyfield/
My usage:
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)
In this example UserVocab (in your case product) can be connected to just one User, but one user can have multiple event_vocabs (products)
Upvotes: 0