Django Formset Redirect with pk/id - python

I'm trying to pass in the parent id of a formset into a view, but it doesn't seem to work for me for some reason. I do this in other apps without issue but this particular one returns "None" as a pk. The only difference being my formset model doesn't usually contain a foreignkey relationship. If I render the parent by itself, I can pass the pk just fine. Please help :)
Exception Value: Reverse for 'company-detail' with keyword
arguments '{'pk': None}' not found. 1 pattern(s) tried:
['customers/(?P[0-9a-z-]+)/detail/$']
'''
urls.py
'''
url(r'^(?P<pk>[0-9a-z-]+)/detail/$', CompanyDetailView.as_view(),
name='company-detail'),
'''
forms.py
'''
class CompanyCreateForm(forms.ModelForm):
class Meta:
model = CompanyModel
fields = [
'name',
'website',
'rate',
]
widgets = {
'name': forms.TextInput(attrs={
'class': 'form-control',
'placeholder': ''}),
'website': forms.URLInput(attrs={
'class': 'form-control',
'placeholder': ''}),
'rate': forms.NumberInput(attrs={
'class': 'form-control',
'placeholder': ''}),
}
SitesFormSet = inlineformset_factory(
CompanyModel,
SiteModel,
fields=('street1',
'street2',
'city',
'state',
'zipcode',
'country',
'phone',
'distance',
),
widgets={
'street1': forms.TextInput(attrs={
'class': 'form-control'
}),
'street2': forms.TextInput(attrs={
'class': 'form-control'
}),
'city': forms.TextInput(attrs={
'class': 'form-control'
}),
'state': forms.TextInput(attrs={
'class': 'form-control'
}),
'zipcode': forms.NumberInput(attrs={
'class': 'form-control'
}),
'country': forms.TextInput(attrs={
'class': 'form-control'
}),
'phone': forms.TextInput(attrs={
'class': 'form-control'
}),
'distance': forms.NumberInput(attrs={
'class': 'form-control'
})
},
extra=1
)
'''
views.py
'''
def companycreateview(request):
if request.method == 'POST':
companyform = CompanyCreateForm(request.POST)
if companyform.is_valid():
company = companyform.save(commit=False)
sitesform = SitesFormSet(request.POST, request.FILES, instance=company)
if sitesform.is_valid():
company.save()
sitesform.save()
return redirect('customers:company-detail', pk=company.pk)
else:
companyform = CompanyCreateForm()
sitesform = SitesFormSet()
context = {
'company': companyform,
'sites': sitesform,
}
return render(request, 'customers/new-company.html', context)
class CompanyDetailView(DetailView):
model = CompanyModel
context_object_name = 'company'
template_name = 'customers/company-detail.html'
def get_context_data(self, **kwargs):
context = super(CompanyDetailView, self).get_context_data(**kwargs)
context['sites'] = SiteModel.objects.filter(company=self.get_object())
context['contacts'] = ContactModel.objects.filter(site__company=self.get_object())
context['reports'] = ServiceReportModel.objects.filter(site__company=self.get_object())
return context
'''
new-company.html.html
'''
<form action="" method="post">
{% csrf_token %}
<div class="form-row">
<div class="form-group col-md-12 form-col-md form-col-right-just {% if report.equipment.errors %}bg-danger{% endif %}">
<label for="{{ company.name.id_for_label }}"><Strong>Company Name</Strong></label></a>
{{ company.name }}
</div>
</div>
<div class="form-row">
<div class="form-group col-md-12 form-col-md form-col-right-just {% if report.equipment.errors %}bg-danger{% endif %}">
<label for="{{ company.website.id_for_label }}"><Strong>Website</Strong></label></a>
{{ company.website }}
</div>
</div>
<div class="form-row">
<div class="form-group col-md-12 form-col-md form-col-right-just {% if report.equipment.errors %}bg-danger{% endif %}">
<label for="{{ company.rate.id_for_label }}"><Strong>Hourly Rate</Strong></label></a>
{{ company.rate }}
</div>
</div>
{{ sites.management_form }}
{{ sites.non_form_errors }}
{% for child_form in sites %}
{{ child_form.sites_id.as_hidden }}
{{ child_form.company.as_hidden }}
<div class="form-row">
<div class="form-group col-md-12 form-col-md">
<label for="{{ child_form.id_for_label }}"><Strong>{{ child_form.label }}</Strong></label>
{{ child_form }}
{% if child_form.errors %}
{% for error in child_form.errors %}
{{ error|escape }}
{% endfor %}
{% endif %}
</div>
</div>
{% endfor %}
<div class="form-row">
<div class="form-group col-md-12 form-col-md form-col-left-just">
<button type="submit" class="btn btn-primary btn-detail"><Strong>Submit</Strong></button>
</div>
</div>
</form>

I think you need to make a small change to your url patterns. The error shows that the following pattern found no matches:
['customers/(?P[0-9a-z-]+)/detail/$']
Try adding <pk> directly after ?P:
customers/(?P<pk>[0-9a-z-]+)/detail/$

In your urls.py:
I think you missed pk in urlpatterns.
url('customers/(?P<pk>[0-9a-z-]+)/detail/$',.......)
In you views.py:
As your coding indentation if somehow sitesform is invalid then it'll try to redirect. But company is not saved yet into database. So pk is None. The code should be like below:
if companyform.is_valid():
company = companyform.save(commit=False)
sitesform = SitesFormSet(request.POST, request.FILES, instance=company)
if sitesform.is_valid():
company.save()
sitesform.save()
return redirect('customers:company-detail', pk=company.pk)

Related

How do I show a form and 2 inputs to upload multiple images in the template and in the view?

I want to make an input that uploads multiple images. I have been reviewing some tutorials and my experience makes me not understand many things.
I placed a view but in the template, where the input should appear, this appears:
<QuerySet []>
Obviously that should not be there, the input should appear that uploads the images when clicked. Can you see my code? can you give me a hint?
html
<form enctype="multipart/form-data" method="post">
{% csrf_token %}
<div class="col-md-4">
<div class="mb-3">
<label class="form-label">Insurance company</label>
{{ form.compañia_seguros }}
<div class="invalid-feedback">
Please provide a website.
</div>
</div>
</div>
</div>
<div class="row mb-3">
<div class="col-md-4">
<div class="mb-3">
<label>Cliente</label>
{{ form.cliente }}
</div>
</div>
</div>
<div class="tab-pane" id="pictures" role="tabpanel">
<div>
{{ images }}
<label for="file-input" class="btn btn-outline-success">Upload images</label>
<p id="num-of-files">No files chosen</p>
<div id="images"></div>
</div>
</div>
<div class="tab-pane" id="warranty" role="tabpanel">
<div>
{{ garantias }}
<label for="file-inputz" class="btn btn-outline-success">Upload images</label>
<p id="num-of-filez">No files chosen</p>
<div id="imagez"></div>
</div>
<br>
<button class="btn btn-primary mb-3" type="submit" value="Post">Save</button>
</div>
</form>
views.py
def create_carros(request):
if request.method == "POST":
form = CarroForm(request.POST)
images = request.FILES.getlist('fotosCarro')
garantias = request.FILES.getlist('garantia')
for image in images:
Carro.objects.create(fotosCarro=image)
for garantia in garantias:
Carro.objects.create(garantias=garantia)
form = CarroForm(request.POST)
images = FotosCarro.objects.all()
garantias = Garantia.objects.all()
return render(request, 'carros/carros-form-add.html', {'images': images,'garantias': garantias,'form':form})
models.py
class Carro(models.Model):
compañia_seguros=models.CharField(max_length=255, null=True)
cliente= models.ForeignKey(Clientes, on_delete=models.SET_NULL, null=True)
fecha_registros = models.DateTimeField(default=datetime.now, null=True)
def __str__(self):
return f'{self.compañia_seguros}{self.cliente}' \
f'{self.fecha_registros}'
class FotosCarro(models.Model):
carro = models.ForeignKey(Clientes, on_delete=models.SET_NULL, null=True)
fotosCarro=models.ImageField(null=True, upload_to="images/")
class Garantia(models.Model):
carro = models.ForeignKey(Clientes, on_delete=models.SET_NULL, null=True)
garantia=models.ImageField(null=True, upload_to="images/")
forms.py
class CarroForm(forms.ModelForm):
class Meta:
model=Carro
fields = ['compañia_seguros','cliente']
exclude = ['fecha_registros']
widgets = {
'compañia_seguros': forms.TextInput(
attrs={
'class': 'form-control'
}
),
'cliente': forms.Select(
attrs={
'class': 'form-select'
}
),
'fecha_registros': forms.DateInput(
attrs={
'class': 'form-control',
}
),
}
class FotosForm(forms.ModelForm):
model = FotosCarro
widgets = {
'fotosCarro':forms.FileInput(
attrs={
'class': 'type-file',
'multiple': True,
'id': 'file-input',
'onchange':'preview()',
}
),
}
class GarantiaForm(forms.ModelForm):
model = Garantia
widgets = {
'garantia':forms.FileInput(
attrs={
'class': 'type-file',
'multiple': True,
'id': 'file-inputz',
'onchange': 'previewz()',
}
),
}
Now that you have separated out FotosCarro and Garantia as their own models, I assume that Carro can have more than one of each of these. This means your form needs to be a bit more complex. To include "subforms" for related models in the parent form, you can to use inline formsets. This will allow you to upload images for multiple FotosCarros and Grantias for a single Carro.

Dynamically save the form

I am trying not to use formset in my form. Instead of that, I trying to create form dynamically and save all forms data in DB. Currently, I can create a dynamic form, but the thing is I fail to save all data from the form even though I create multiple forms. Now my code only can save only one form. But I want to save the whole form (with multiple form data) in DB.
views.py
def create_order(request):
from django import forms
form = OrderForm()
if request.method == 'POST':
forms = OrderForm(request.POST)
if forms.is_valid():
po_id = forms.cleaned_data['po_id']
supplier = forms.cleaned_data['supplier']
product = forms.cleaned_data['product']
part = forms.cleaned_data['part']
order = Order.objects.create(
po_id=po_id,
supplier=supplier,
product=product,
part=part,
)
return redirect('order-list')
context = {
'form': form
}
return render(request, 'store/addOrder.html', context)
forms.py
class OrderForm(forms.ModelForm):
class Meta:
model = Order
fields = ['supplier', 'product', 'part','po_id']
widgets = {
'supplier': forms.Select(attrs={'class': 'form-control', 'id': 'supplier'}),
'product': forms.Select(attrs={'class': 'form-control', 'id': 'product'}),
'part': forms.Select(attrs={'class': 'form-control', 'id': 'part'}),
}
HTML
<form action="#" method="post" id="form-container" novalidate="novalidate">
{% csrf_token %}
<div class="form">
<div class="form-group">
<label for="po_id" class="control-label mb-1">ID</label>
{{ form.po_id }}
</div>
<div class="form-group">
<label for="supplier" class="control-label mb-1">Supplier</label>
{{ form.supplier }}
</div>
<div class="form-group">
<label for="product" class="control-label mb-1">Product</label>
{{ form.product }}
</div>
<div class="form-group">
<label for="part" class="control-label mb-1">Part Name</label>
{{ form.part }}
</div>
</div>
<button id="add-form" type="button">Add Another Order</button>
<div>
<button id="payment-button" type="submit" class="btn btn-lg btn-success btn-block">
<span id="payment-button-amount">Save</span>
</button>
</div>
</form>
<script>
let poForm = document.querySelectorAll(".form")
let container = document.querySelector("#form-container")
let addButton = document.querySelector("#add-form")
let totalForms = document.querySelector("#id_form-TOTAL_FORMS")
let formNum = poForm.length-1
addButton.addEventListener('click', addForm)
function addForm(e){
e.preventDefault()
let newForm = poForm[0].cloneNode(true)
let formRegex = RegExp(`form-(\\d){1}-`,'g')
formNum++
newForm.innerHTML = newForm.innerHTML.replace(formRegex, `form-${formNum}-`)
container.insertBefore(newForm, addButton)
totalForms.setAttribute('value', `${formNum+1}`)
}
</script>
if request.method == 'POST':
forms = OrderForm(request.POST)
if forms.is_valid():
po_id = forms.cleaned_data['po_id']
supplier = forms.cleaned_data['supplier']
product = forms.cleaned_data['product']
part = forms.cleaned_data['part']
forms.save() # add save here
order = Order.objects.create(
po_id=po_id,
supplier=supplier,
product=product,
part=part,
)
return redirect('order-list')

Save random integer into form of Django

I am trying to save po_id as a unique key of the "Order table". So I am generating a random number in the Order Form. But the issue is that somehow I can not save the form, even though all the fields are filled up.
models.py
def random_string():
return str(random.randint(10000, 99999))
class Order(models.Model):
po_id = models.CharField(max_length=4, default = random_string)
supplier = models.ForeignKey(Supplier, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
forms.py
class OrderForm(forms.ModelForm):
class Meta:
model = Order
fields = ['supplier', 'product', 'po_id']
widgets = {
'supplier': forms.Select(attrs={'class': 'form-control', 'id': 'supplier'}),
'product': forms.Select(attrs={'class': 'form-control', 'id': 'product'}),
}
views.py
def create_order(request):
from django import forms
form = OrderForm()
if request.method == 'POST':
forms = OrderForm(request.POST)
if forms.is_valid():
po_id = forms.cleaned_data['po_id']
supplier = forms.cleaned_data['supplier']
product = forms.cleaned_data['product']
order = Order.objects.create(
po_id=po_id,
supplier=supplier,
product=product,
)
return redirect('order-list')
context = {
'form': form
}
return render(request, 'store/addOrder.html', context)
Order.html
<form action="#" method="post" novalidate="novalidate">
{% csrf_token %}
<div class="form-group">
<label for="po_id" class="control-label mb-1">ID</label>
{{ form.po_id }}
</div>
<div class="form-group">
<label for="supplier" class="control-label mb-1">Supplier</label>
{{ form.supplier }}
</div>
<div class="form-group">
<label for="product" class="control-label mb-1">Product</label>
{{ form.product }}
</div>
<div>
<button id="payment-button" type="submit" class="btn btn-lg btn-success btn-block">
<span id="payment-button-amount">Save</span>
</button>
</div>
Can help me with how I can solve the issue?

Django initial_forms.is_valid() returns false

My goal is to edit/update existing data. I am able to display existing data and add new data but not edit data. My model are Recipe and Ingredient. I am using modelformset_factory to add ingredients to recipe.
Here is the forms.py:
class RecipeModelForm(forms.ModelForm):
class Meta:
model = Recipe
fields = ('name', )
labels = {
'name': 'Recipe Name'
}
widgets = {
'name': forms.TextInput(attrs={
'class': 'form-control',
'placeholder': 'Enter Recipe Name here'
}
)
}
IngredientFormset = modelformset_factory(
Ingredient,
fields=('name', 'amount', 'unit'),
labels={
'name': 'Ingredient Name',
'amount': 'Amount',
'unit': 'Unit'
},
extra=1,
widgets={
'name': forms.TextInput(
attrs={
'class': 'form-control',
'placeholder': 'Enter Ingredient Name here'
}
),
'amount': forms.TextInput(
attrs={
'class': 'form-control',
'placeholder': 'Enter Amount here'
}
),
'unit': forms.Select(
attrs={
'class': 'form-control',
'placeholder': 'Enter Unit here'
}
)
},
can_delete=True
)
views.py:
#login_required
def update_recipe(request, pk):
template_name = 'recipe/create_with_ingredients.html'
# template_name = 'recipe/update.html'
recipe = Recipe.objects.get(id=pk, author=request.user)
ingredients = Ingredient.objects.filter(recipe=recipe)
if request.method == 'GET':
recipeform = RecipeModelForm(instance=recipe)
formset = IngredientFormset(queryset=ingredients)
elif request.method == 'POST':
recipeform = RecipeModelForm(request.POST, instance=recipe)
formset = IngredientFormset(request.POST, queryset=ingredients)
if recipeform.is_valid(): # and formset.is_valid():
recipe = recipeform.save(commit=False)
recipe.author = request.user
recipe.save()
for form in formset.initial_forms:
print(form.is_valid())
if form.is_valid():
data = form.cleaned_data
for form in formset:
if form.is_valid():
data = form.cleaned_data
if data:
ingredient = form.save(commit=False)
ingredient.recipe = recipe
ingredient.author = request.user
ingredient.save()
return redirect('recipe:list-recipe')
context = {
'recipeform': recipeform,
'formset': formset,
}
return render(request, template_name, context)
My html template:
{% extends "recipe/base.html" %}
{% block container %}
{% if heading %}
<h3>{{heading}}</h3>
{% endif %}
<form class="form-horizontal" method="POST" action="">
{% csrf_token %}
<div class="row spacer">
<div class="col-6">
<label>{{recipeform.name.label}}</label>
</div>
<div class="col-8">
<div class="input-group">
{{recipeform.name}}
</div>
</div>
</div>
{{ formset.management_form }}
{% for form in formset %}
{% if form.subject.errors %}
<ol>
{% for error in form.subject.errors %}
<li><strong>{{ error|escape }}</strong></li>
{% endfor %}
</ol>
{% endif %}
<!-- {% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-danger">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endfor %}
{% for error in form.non_field_errors %}
<div class="alert alert-danger">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endif %} -->
<div class="row form-row spacer">
<table>
<div class="col-2">
<tr>
<th><label>{{form.name.label}}</label></th>
<th><label>{{form.amount.label}}</label></th>
<th><label>{{form.unit.label}}</label></th>
</tr>
</div>
<div class="col-4">
<tr>
<div class="input-group">
<td>{{form.name}}</td>
<td>{{form.amount}}</td>
<td>{{form.unit}}</td>
<div class="input-group-append">
<td><button class="btn btn-success add-form-row">+</button></td>
</div>
</tr>
</div>
</div>
</table>
</div>
{% endfor %}
<div class="row spacer">
<div class="col-4 offset-0">
<button type="submit" class="btn btn-block btn-primary">Create</button>
</div>
</div>
</form>
{% endblock %}
First I had if recipeForm.is_valid() and formset.is_valid() but this never result to True (formset fails). So, I removed second check and instead validate each form in formset. With this approach I found out that initial_forms (existing data) are not in formset. Therefore, to get initial forms I get it from formset.initial_forms this gives me forms with edited data and existing data but when I call form.is_valid() it fails. I am not sure why does initial data fail to valid when they are already in database. How can I update edited forms to existing data in database?
Try checking form validation errors first.
this answer may help you doing this,
if not, check this documentation.
Give us an additional feedback with error messages in case my solution wasn't enough.

always getting "This field is required" error on Django form

I had a form with some fields and it was working fine. But when adding new field in the Model django raise an error
when I run the server and click on submit then it shows error for the new field This field is required although I am providing data for this field in the form.
Model.py
class UserInformation(models.Model):
firstName = models.CharField(max_length=128)
lastName = models.CharField(max_length=128)
userName = models.CharField(max_length=128)
institution = models.CharField(choices = [("#xyz.org","XYZ"), ("#abc.edu","ABC")], max_length=128)
userEmail = models.CharField(default="N/A", max_length=128)
phoneNumber = models.CharField(max_length=128)
orchidNumber = models.CharField(max_length=128)
PI = models.CharField(max_length=128)
PIUsername = models.CharField(max_length=128)
PIInstitution = models.CharField(default="N/A",choices = [("#xyz.org","XYZ"), ("#abc.edu","ABC")], max_length=128)
PIEmail = models.CharField(default="N/A", max_length=128)
PIPhoneNumber = models.CharField(max_length=128)
In this model
PIEmail is the field which I have added.
forms.py
class UserInformationForm(ModelForm):
firstName = forms.CharField(max_length=254,
widget=forms.TextInput({
'class': 'form-control',
}))
lastName = forms.CharField(
widget=forms.TextInput({
'class': 'form-control',
}))
userName = forms.CharField(
widget=forms.TextInput({
'class': 'form-control',
}))
institution = forms.ChoiceField( choices = [("#xyz.org","XYZ"), ("#abc.edu","ABC")]
,widget=forms.Select({
'class': 'form-control',
}))
phoneNumber = forms.CharField( required=False,
widget=forms.TextInput({
'class': 'form-control',
}))
orchidNumber = forms.CharField( required=False,
widget=forms.TextInput({
'class': 'form-control',
}))
PI = forms.CharField(
widget=forms.TextInput({
'class': 'form-control',
}))
PIUsername = forms.CharField(
widget=forms.TextInput({
'class': 'form-control',
}))
ctsaPIInstitution = forms.ChoiceField( choices = [("#xyz.org","XYZ"), ("#abc.edu","ABC")]
,widget=forms.Select({
'class': 'form-control',
}))
PIPhoneNumber = forms.CharField(
widget=forms.TextInput({
'class': 'form-control',
}))
userEmail = forms.CharField( required=False,
widget=forms.TextInput({
'class': 'form-control',
}))
PIEmail = forms.CharField( required=False,
widget=forms.TextInput({
'class': 'form-control',
}))
class Meta:
model = UserInformation
exclude = ()
and here is my register.html
<div class="row">
<section id="registerForm">
<div style="font-size:15px; color:red;">
The fields marked with an asterisk (*) are mandatory.
</div><br/>
<form method="post" action=".">{% csrf_token %}
<div class="form-group">
<label for="id_firstName" >First Name (*)</label>
{{ form.firstName }}
</div>
<div class="form-group">
<label for="id_lastName" >Last Name (*)</label>
{{ form.lastName }}
</div>
<div class="form-group">
<label for="id_email">Username (*)</label>
{{ form.userName }}
</div>
<div class="form-group">
<label for="id_intitution">Institution (*)</label>
{{ form.institution }}
</div>
<div class="form-group">
<label for="id_phone" >Contact Number</label>
{{ form.phoneNumber }}
</div>
<div class="form-group">
<label for="id_orcid">Orcid ID (Get Orcid ID)</label>
{{ form.orchidNumber }}
</div>
<div class="form-group">
<label for="id_ctsaPI">Prinicipal Investigator (*)</label>
{{ form.PI }}
</div>
<div class="form-group">
<label for="id_PI">CTSA Prinicipal Investigator Username (*)</label>
{{ form.PIUsername }}
</div>
<div class="form-group">
<label for="id_ctsaPI">Prinicipal Investigator Institute (*)</label>
{{ form.PIInstitution }}
</div>
<div class="form-group">
<label for="id_PIName"> Prinicipal Investigator Phone Number (*)</label>
{{ form.PIPhoneNumber }}
</div>
<div class="form-group">
<label for="id_UserEmail">User Email (*)</label>
{{ form.userEmail }}
</div>
<div class="form-group">
<label for="id_PI">PI Email (*)</label>
{{ form.PIEmail }}
</div>
<div class="form-group" >
<br/>
<input type="submit" value="Submit" class="btn btn-primary" />
</div>
</form>
</section>
view.py
#csrf_protect
def register(request):
if request.method == 'POST':
form = UserInformationForm(request.POST)
if form.is_valid(): //// here it is breaking
form.save()
else:
form = UserInformationForm()
variables = { 'form': form }
return render(request, 'registration/register.html',variables)
I am not sure what is wrong in this code
I'm not sure if this helps but sometimes I find the errors returned look like a bit of a red herring and end up driving me mad for hours on end. I am no expert and from where I am sitting the code for your form looks fine to me which is probably why it was working before. However in your html file you have two labels specified with the same id, the second one just happens to be on the PIEmail field that you have recently added. Coincidence? Maybe! It's a long shot but perhaps change that initially and see if it makes any difference.
Change:
<div class="form-group">
<label for="id_PI">PI Email (*)</label>
{{ form.PIEmail }}
</div>
to:
<div class="form-group">
<label for="id_PIEmail">PI Email (*)</label>
{{ form.PIEmail }}
</div>
Note: The other instance is on the PIUsername field.

Categories