I am attempting to take in a form for update or delete, run the process and either return the updated url, or the updated list of objects. I've got the dynamic url building working, but when I hit submit I get a 404. I am struggling with the how to process the POST, as it doesn't even seem to be hitting that far in the code. Code below:
urls.py
path("customers/", views.customers, name="customers"),
path("customers/customer/<int:id>/", views.customer),
forms.py
class CustomerMaintForm(ModelForm):
class Meta:
model = AppCustomerCst
fields = ('id_cst', 'is_active_cst', 'name_cst', 'address_1_cst', 'address_2_cst', 'address_3_cst',
'city_cst', 'state_cst', 'zip_cst', 'country_cst', 'salesrep_cst', 'type_cst',
'is_allowed_flat_cst', 'iddef_cst', 'date_created_cst', 'date_suspended_cst',
'date_first_tran_cst', 'date_last_tran_cst', 'is_credit_hold_cst',
'old_balance_cst', 'balance_notify_cst', 'balance_statement_cst',
'balance_conversion_cst', 'balance_cst', 'receive_emails_cst',
'contact_domain_cst'
)
labels = {'id_cst': 'Customer ID', 'is_active_cst': 'Active?', 'name_cst': mark_safe('<p>Name'),
'address_1_cst': 'Address 1',
'address_2_cst': 'Address 2', 'address_3_cst': 'Address 3', 'city_cst': 'City', 'state_cst': 'State',
'zip_cst': 'Zip', 'country_cst': 'Country', 'salesrep_cst': 'Sales Rep', 'type_cst': 'Type',
'is_allowed_flat_cst': 'Allowed Flat?', 'iddef_cst': mark_safe('<p>Id'),
'date_created_cst': 'Created Date', 'date_suspended_cst': 'Suspended Date',
'date_first_tran_cst': 'First Tran Date', 'date_last_tran_cst': 'Last Tran Date',
'is_credit_hold_cst': 'Credit Hold?', 'old_balance_cst': 'Old Balance',
'balance_notify_cst': 'Balance Notify', 'balance_statement_cst': 'Balance Statement',
'balance_conversion_cst': 'Balance Conversion', 'balance_cst': 'Current Balance',
'receive_emails_cst': 'Receive Emails?', 'contact_domain_cst': mark_safe('<p>Contact Domain')}
views.py
def customer(request, id):
if request.method == "GET":
obj = AppCustomerCst.objects.get(id_cst=id)
instance = get_object_or_404(AppCustomerCst, id_cst=id)
form = CustomerMaintForm(request.POST or None, instance=instance)
ContactFormSet = modelformset_factory(AppContactCnt, can_delete=True, fields=(
'name_cnt', 'phone_cnt', 'email_cnt', 'note_cnt', 'receives_emails_cnt'))
formset = ContactFormSet(queryset=AppContactCnt.objects.filter(idcst_cnt=id), prefix='contact')
tpList = AppCustomerTpRel.objects.filter(idcst_rel=id).select_related('idcst_rel', 'idtrp_rel').values(
'idtrp_rel__id_trp', 'idtrp_rel__tpid_trp', 'idtrp_rel__name_trp', 'sender_id_rel', 'category_rel',
'cust_vendor_rel')
TPFormSet = formset_factory(TPListForm, can_delete=True)
tp_formset = TPFormSet(initial=tpList, prefix='tp')
doc_list = DocData.objects.document_list(id)
DocFormSet = formset_factory(DocumentListForm)
DocFormSet = formset_factory(DocumentListForm)
doc_formset = DocFormSet(initial=doc_list, prefix='doc')
context = {'form': form, 'formset': formset, 'tp_formset': tp_formset, 'doc_formset': doc_formset, 'id': id}
print(form.errors)
return render(request, 'customer.html', context=context)
elif '_edit' in request.POST:
print(id, request.POST)
cust_name = request.POST['name_cst']
instance = get_object_or_404(AppCustomerCst, name_cst=cust_name)
form = CustomerMaintForm(request.POST, instance=instance)
if form.is_valid():
form.save()
return HttpResponseRedirect("/customers/customer/{id}")
else:
context = {'form': form, 'contact_form': contact_form}
return redirect(request, 'customer.html', context=context)
elif '_delete' in request.POST:
cust_name = request.POST['name_cst']
instance = get_object_or_404(AppCustomerCst, name_cst=cust_name)
form = CustomerMaintForm(request.POST, instance=instance)
if form.is_valid():
AppCustomerCst.objects.filter(id_cst=id).delete()
return render(request, 'customers.html')
else:
pass
customer.html
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% url customer string %}
{% block content %}
<form method="post" action="/customer">
{% csrf_token %}
<div style="height:300px;overflow:auto;">
{{ form }}
</div>
<input type="submit" value="Edit" name="_edit">
<input type="submit" value="Delete" name="_delete">
</form>
{% endblock %}
The 404 is because the form sends a POST to /customer and your URLs are
/customers/
/customers/customer/<int:id>/
So I'd first add a name to your path so it becomes something like path("customers/customer/<int:id>/", views.customer, name='customer')
Then change your form action to use django URL reversal;
<form method="post" action="{% url 'customer' id=id %}">
By doing this it'll generate the URL for you based on the ID of the customer form you're on, assuming id is in the context which it appears to be from your view code.
That should solve the 404 and improve things a little.
Related
When I fill out my form with its file, it apparently submits, but when checking it out when editing/uploading, all data in the form shows up except my file. So, I cannot access it at all. I guess it probably has something to do with my views.py (the function is for both, save a form for the first time and visualizing them), so here it goes
#views.py
def contract_form(request, id=0):
if request.method == "GET":
if id == 0:
form = ContractsForm(request.FILES)
else:
contratos = Contratos.objects.get(pk=id)
form = ContractsForm( instance=contratos)
return render(request,"contracts_form.html", {'form':form})
else:
if id == 0:
form = ContractsForm(request.POST, request.FILES)
else:
contratos = Contratos.objects.get(pk=id)
form = ContractsForm(request.POST, request.FILES, instance= contratos, )
if form.is_valid():
form.save()
messages.success(request, "Form submission successful")
else:
messages.error(request, "Error, contract not submitted")
return redirect('/contracts')
Just in case, every other instance that has something to do with the upload file:
#models.py
attached_file=models.FileField(upload_to="media", blank=True)
My form is stated with <form enctype="multipart/form-data" action="" method="post" autocomplete="off" class="row g-3">
#contracts_form.html
<label for="{{ form.subject.id_for_label }}">Attached File:</label>
{{form.attached_file}}
{% if Contracts.media %}
{% endif %}
#settings.py
MEDIA_ROOT=os.path.join(BASE_DIR, 'uploads/')
MEDIA_URL="/contracts-media/"
path('contracts/edit/<int:id>', views.contract_form, name='edit'), #edit/update form
path('contracts/add', views.contract_form, name = 'new-contract'), #add a contract
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
````
There's no text in your link tag
Try
Wonderful Linkiness
My task to make pre-populated content of the page, like this:
content
content = "Sample text"
content = forms.CharField(widget=forms.Textarea, initial = content)
I need something like above, can you help me with realising that in code
class EditPageForm(forms.Form):
content = forms.CharField(widget=forms.Textarea)
def editPage(request, title):
content = util.get_entry(title)
if request.method == "POST":
form = EditPageForm(request.POST)
if form.is_valid():
new_content = form.cleaned_data["content"]
util.save_entry(title, new_content)
return HttpResponseRedirect(reverse("encyclopedia:entry", kwargs={'title': title}))
EditPageForm.initial = content
return render(request, "encyclopedia/editpage.html", {
"form": NewSearchForm,
"editPageForm": EditPageForm,
"title": title
})
Html code:
<form action="{% url 'encyclopedia:editpage' title=title%}" method="post">
<div>
<h3>Content:</h3>
{% csrf_token %}
{{ editPageForm }}
</div>
<input type="Submit">
</form>
You can use widget attributes to add placeholder text that you'd like in your form which can be dynamic and less lines to add.
class EditPageForm(forms.Form):
content = forms.CharField(widget=forms.Textarea(attrs={'placeholder': 'THIS IS MY PLACEHOLDER TEXT'}))
Thank everyone for help, the solution was found.
return render(request, "encyclopedia/editpage.html", {
"form": NewSearchForm,
"editPageForm": EditPageForm(initial={'content': content}),
"title": title
})
Now how that looks like,
You can pass an initial=… parameter [Django-doc] to the form with as value a dictionary with initial values:
from django.shortcuts import redirect
def editPage(request, title):
content = util.get_entry(title)
if request.method == 'POST':
editPageForm = EditPageForm(request.POST, initial={'content': content})
if form.is_valid():
new_content = form.cleaned_data['content']
util.save_entry(title, new_content)
return redirect('encyclopedia:entry', title=title)
else:
editPageForm = EditPageForm(, initial={'content': content})
return render(request, 'encyclopedia/editpage.html', {
'form': NewSearchForm,
'editPageForm': editPageForm,
'title': title
})
That being said, it might be better to work with models and a ModelForm [Django-doc] since this can remove a lot of boilerplate code.
I want to use Ajax in Django to handle the view of my checkout form after it has been submitted. After the form is submitted, I want it to go to :
return HttpResponseRedirect(reverse(str(next_page))+"?address_added=True") , i.e http://127.0.0.1:8000/checkout/?address_added=True
But for some reason, it is not going there. Rather it's being going to http://127.0.0.1:8000/checkout/?csrfmiddlewaretoken=W4iXFaxwpdtbZLyVI0ov8Uw7KWOM8Ix5GcOQ4k3Ve65KPkJwPUKyBVcE1IjL3GHa&address=123+Main+Street&address2=&state=MA&country=USA&zipcode=55525&phone=%28877%29+314-0742&billing=on
As a result, the form data is also not getting saved. I was thinking if it were because of the new version of Django.
What I want to do is that after they submit the place order button, the form is going to be None, i.e disappear and then I would add a credit card form there for payment. But it is not happening. What is wrong here? How can I do this or is there a better way to do this?
My forms.py:
class UserAddressForm(forms.ModelForm):
class Meta:
model = UserAddress
fields = ["address", "address", "address2", "state", "country", "zipcode", "phone", "billing"]
My accounts.views.py:
def add_user_address(request):
try:
next_page = request.GET.get("next")
except:
next_page = None
if request.method == "POST":
form = UserAddressForm(request.POST)
if form.is_valid():
new_address = form.save(commit=False)
new_address.user = request.user
new_address.save()
if next_page is not None:
return HttpResponseRedirect(reverse(str(next_page))+"?address_added=True")
else:
raise Http404
My orders.views.py:
#login_required()
def checkout(request):
try:
the_id = request.session['cart_id']
cart = Cart.objects.get(id=the_id)
except:
the_id = None
return redirect(reverse("myshop-home"))
try:
new_order = Order.objects.get(cart=cart)
except Order.DoesNotExist:
new_order = Order(cart=cart)
new_order.cart = cart
new_order.user = request.user
new_order.order_id = id_generator()
new_order.save()
except:
return redirect(reverse("cart"))
try:
address_added = request.GET.get("address_added")
except:
address_added = None
if address_added is None:
address_form = UserAddressForm()
else:
address_form = None
if new_order.status == "Finished":
#cart.delete()
del request.session['cart_id']
del request.session['items_total']
return redirect(reverse("cart"))
context = {"address_form": address_form, "cart": cart}
template = "orders/checkout.html"
return render(request, template, context)
My urls.py:
path('ajax/add_user_address', accounts_views.add_user_address, name='ajax_add_user_address'),
My checkout.html:
<form method="POST" action="{% url 'ajax_add_user_address' %}?redirect=checkout">
{% csrf_token %}
<fieldset class="form-group">
{{ address_form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-dark" type="submit">Place Order</button>
</div>
</form>
I would personally split these up in two views, because they do different stuff.
But, if you want to keep it that way, you can do the following:
First of all, because you are making an AJAX Request, you should return a JsonResponse object.
In your view you can render the checkout.html and pass it as a context variable to your json response:
def add_user_address(request):
...
data = dict()
context = {
'address_form': form,
...
}
data['html_form'] = render_to_string("checkout.html",
context,
request=request)
return JsonResponse(data)
And in your $.ajax success function you can do the following
success: function(data) {
// console.log(data);
$("div-to-replace-html").html(data.html_form);
}
I have a scheduling app where patients can register for appointments. When I submit the form for a new appointment, I get the value error.
views.py
def patient_portal(request):
appointments = Appointment.objects.filter(patient=request.user.patient.pid)
data_input = request.GET.get('date')
selected_date = Appointment.objects.filter(date = data_input).values_list('timeslot', flat=True)
available_appointments = [(value, time) for value, time in Appointment.TIMESLOT_LIST if value not in selected_date]
doctor = Patient.objects.get(doctor=request.user.patient.doctor).doctor
print(doctor)
if request.method == 'POST':
form = AppointmentForm(initial={'doctor': doctor,'patient': request.user.patient}, instance=request.user.patient)
if form.is_valid():
form.save()
return redirect('../home/')
else:
form = AppointmentForm(initial={'doctor': doctor,'patient': request.user.patient}, instance=request.user.patient)
return render(request, 'scheduling/patient.html', {"form" : form, "appointments" : appointments, "available_appointments" : available_appointments, "data_input": data_input, "doctor": doctor})
patient.html:
<form method="post" action="" id="timeslot" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="btn btn-primary">Submit</button>
</form>
forms.py:
class AppointmentForm(forms.ModelForm):
class Meta:
model = Appointment
fields = ('doctor','patient','date','timeslot')
Your view must always return an HTTP response. At the moment, your code doesn't handle the case when request.method == 'POST', but the form is invalid.
You can fix your code by de-indenting the final return statement, to move it outside of the else block:
def patient_portal(request):
...
if request.method == 'POST':
form = AppointmentForm(initial={'doctor': doctor,'patient': request.user.patient}, instance=request.user.patient)
if form.is_valid():
form.save()
return redirect('../home/')
else:
form = AppointmentForm(initial={'doctor': doctor,'patient': request.user.patient}, instance=request.user.patient)
return render(request, 'scheduling/patient.html', {"form" : form, "appointments" : appointments, "available_appointments" : available_appointments, "data_input": data_input, "doctor": doctor})
I'm using Django 2.0. This is my forms.py:
class PostcodeForm(forms.Form):
postcode = forms.CharField(required=True, widget=forms.TextInput(
attrs={
'placeholder': "enter a postcode",
}
))
def clean_postcode(self):
postcode = self.clean_data.get('postcode', '')
print('clean_postcode', postcode)
if postcode != 'something':
raise forms.ValidationError(_("Please enter a valid postcode"), code='invalid')
return data
And my views.py:
def index(request):
form = PostcodeForm()
context = {
'form': form
}
return render(request, 'index.html', context)
And my index.html:
<form class="form-inline" id="lookup_postcode" action="{% url 'lookup_postcode' %}" method="get">
{% csrf_token %}
{{ form.non_field_errors }}
{{ form.postcode.errors }}
{{ form.postcode }}
<button type="submit">Submit</button>
</form>
But when I type in any value other than 'something', the form still submits. I also don't see any print statements in the console, so it looks as though the validator just isn't being run.
What am I doing wrong?
At the moment you are always doing form = PostcodeForm(), for GET and POST requests. That means that the form is not bound to any data, so it will never be valid or have any errors.
In Django, a typical view to process a form looks something like this:
from django.shortcuts import redirect
def index(request):
if request.method == 'POST':
form = PostcodeForm(request.POST)
if form.is_valid():
# form is valid. Process form and redirect
...
return redirect('/success-url/')
else:
form = PostcodeForm()
context = {
'form': form
}
return render(request, 'index.html', context)
For this to work, you'll need to change your form method to 'post'.
<form class="form-inline" id="lookup_postcode" action="{% url 'lookup_postcode' %}" method="post">
If you keep the form method as 'get' then you'll need to bind the form to request.GET instead. You might want to add a check, otherwise you'll get errors for required fields when you first access the index view.
if 'postcode' in request.GET:
# bound form
form = PostcodeForm(request.GET)
else:
# unbound, empty form
form = PostcodeForm()
Use your form as below:
class PostcodeForm(forms.Form):
postcode = forms.CharField(required=True, widget=forms.TextInput(
attrs={
'placeholder': "enter a postcode",
}
))
def clean(self):
postcode = self.cleaned_data.get('postcode', '')
print('clean_postcode', postcode)
if postcode != 'something':
raise forms.ValidationError(_("Please enter a valid postcode"), code='invalid')
return super(PostcodeForm, self).clean()
Everytime you deal with the validity of the posted data, make sure to include form.is_valid() condition in your views.py.