Django unable delete form with data shown - python

i have created a delete function for my forms but it can only delete if i did not display out my information.
However if i try to display the information out on the delete page, the delete function wouldn't work.
i think because when i display the information out, the form isn't valid, hence unable to delete the object.
My views.py
def servicing_entry_delete(request, serv_entry_id):
delete_object = get_object_or_404(serv_entry, id=serv_entry_id)
if request.method == 'POST':
form = Delete_Flying_form(request.POST, instance=delete_object)
if form.is_valid(): # checks CSRF
delete_object.delete()
return HttpResponseRedirect(reversed('hello:servicing_entry')) # wherever to go after deleting
else:
form = Delete_Flying_form(instance=delete_object)
return render(request, 'hello/servicing_entry_delete.html', {'form':form})
My forms.py
class Delete_Flying_form(forms.ModelForm):
class Meta:
model = serv_entry
fields = ('Servicing_Type', 'Time', 'Date','Ic_Clear_Name','Ic_Clear_Time','Ic_Clear_Date')
My deleteconfirmation.html
{% extends 'hello/base.html' %}
{% block content %}
<h1>Delete Servicing Entry</h1>
<p>Are you sure you want to delete this Entry: </p>
{{ form }}
<form action="" method="POST">
{% csrf_token %}
<input type="submit" action="" value="Yes, delete this Entry." />
</form>
{% endblock %}
Without the {{ form }}, i am able to delete the object smoothly but not being able to display any information.
However if i try to display, like this
is there anyway if i could display this few fields and still delete successfully?
My django version is 1.11
with python 2.7.5
Much appreciate!

Related

User doesnt save to database Django

views.py
def registerPage(request):
form = UserCreateForm()
if request.method=='POST':
form=UserCreateForm(request.POST)
if form.is_valid():
user=form.save(commit=False)
user.save()
return redirect('home')
return render(request,'base/signup.html',{'form':form})
model.py
class User(AbstractUser):
name = models.CharField(max_length=200,null=True)
email = models.EmailField(unique=True,null=True)
bio=models.TextField(null=True)
avatar = models.ImageField(upload_to='images/',null=True)
USERNAME_FIELD='email'
REQUIRED_FIELDS=['username']
forms.py
class UserCreateForm(UserCreationForm):
class Meta:
model = User
fields = ['name','email','password1','password2','bio','avatar']
htmltemplate
{% include 'main.html' %}
{% block content %}
<div>
<form method="POST">
{% csrf_token %}
{% for field in form %}
{{field.label}}
{{field}}
{% endfor %}
<input type="submit" value="Register" >
</form>
</div>
{% endblock content %}
when ever i try to sign up on html template it doesnt work but if i do it in admin panel it works how can i solve it ?
First of all, it is generally not recommended to mess with the default User model from django. Its better to create a Profile model with a OneToOneField relationship with the user.
Other than that, your issue lies with your form. Since you have avatar which is an ImageField you need to change your form in a way that it can accept FILES.
So what you need to do is change your form like this:
<form method="post" action="" enctype="multipart/form-data" >
When you are writing client-side code:
use multipart/form-data when your form includes any <input type="file"> elements.
In order to make your POST request valid, you need to also receive your FILES on your view. That can be done by changing your code to:
if request.method=='POST':
form=UserCreateForm(request.POST, request.FILES)
if form.is_valid():
....

How to dynamically delete object using django formset

Django says, i should render inline formset this way:
{{ formset.management_form }}
{% for form in formset %}
{{ form.id }}
{{ form.field_1 }}
{{ form.field_2 }}
<button type="button"> delete </button>
{% endfor %}
<button type="submit"> submit </button>
Ok. But what if i want to delete some formset objects (form) dynamically? User press delete button - i remove form from the DOM, i use ajax to remove object, related to the form from the DATABASE. It works ok till this point. But when user clicks submit - my views.py trying to validate formset:
filled_formset = OrderItemFormSet(request.POST, instance=order)
if filled_formset.is_valid():
and raises error:
MultiValueDictKeyError at /order/cart/
"'orderitem_set-0-id'"
...\market\ordersys\views.py in show_cart
59. if filled_formset.is_valid():
I think it happend because form objects were displayed by django with some regularity (first form got id = orderitem_set-0-id, second = orderitem_set-1-id etc.) And when i deleted first form from the DOM, the regularity was broken - there is no more form with orderitem_set-0-id. But is_valid() still trying to get it dict["orderitem_set-0-id"].
I could use some black magic, substituting django's technical information, displayed in the DOM, restoring disrupted regularity, but is there a better way?
Could you tell me how to properly dynamically delete formset items, please ?
I got no answer for some time, so i did not find any better solution than below. Maybe someome will find it useful.
Ok, the trick is - to have {{form.DELETE}} for any form in your formset in template. It renders as a checkbox (i made it invisible) and i made JS to make it "checked" whenever user press "delete" button. After user press "submit" button, every form, marked for deletion, will NOT be validated by the view during filled_formset.is_valid(). This lets you delete object from database with ajax behind the scene.
The problem was that an ERROR was raised during formset validation. Caused by the form of an object, which was already deleted from database with ajax.
So there are all components:
views.py
def show_cart(request):
OrderItemFormSet = inlineformset_factory(Order, OrderItem, form=OrderItemForm, extra=0, can_delete=True)
order = Order.objects.get(pk=request.session['order'])
if request.method == 'GET':
formset = OrderItemFormSet(instance=order)
return render(request, 'ordersys/cart.html', {'formset': formset})
elif request.method == 'POST':
filled_formset = OrderItemFormSet(request.POST, instance=order)
if filled_formset.is_valid():
filled_formset.save()
return redirect('catalog:index')
else:
return render(request, 'ordersys/cart.html', {'formset': filled_formset})
cart.html
<form action="" method="post">
{{ formset.management_form }}
{% for form in formset %}
{{ form.id }}
{{ form.DELETE|add_class:"not_displayed" }} # custom filter
<img src="{{ form.instance.spec_prod.product.picture.url }}">
{{ form.quantity.label_tag }}
{{ form.quantity }}
{{ form.errors }}
<button type="button">Delete</button>
{% endfor %}
<button type="submit">Submit</button>
</form>
Next, if user press 'DELETE' button, my JavaScript
1. hides form with $(item).css('display', 'none');
2. makes checked form.DELETE checkbox with ItemDelCheckbox.prop('checked', true);
3. sends ajax request to delete item from database (otherwise if user refreshes the page, the item still in the cart)
views.py
def delete_order_item(request): # meets the ajax request
item_id = int(request.POST['item_id'])
order = get_object_or_404(Order, pk=int(request.POST['order_id']))
order.remove_item(item_id)
if order.is_empty(): # if the last item is deleted
order.untie(request.session)
order.delete()
return HttpResponse()
Instead of manually creating the hidden field using {{ form.DELETE }}, you can probably use 'can_delete' while instantiating the formset which does the same. For eg,
ArticleFormSet = formset_factory(ArticleForm, can_delete=True)
Refer can_delete

Why is my flask form validation returning Not a valid choice?

I have been trying to figure out why my Flask form will not properly validate my select field choices even though the choices are coming from the select field options.
My assumption is that the select option when passed back from the server is unicode and is being compared to the choice which is a string, however, I thought coerce=str would fix that. I printed out the form data and request data which is the output below. Why isn't it working?
My code is attached below, removed csrf token key from the output dict. It seems like a very simple thing, but I can't figure it out.
forms.py
class PlatformForm(FlaskForm):
platform_options = [('test', 'Test'), ('test2','Test2')]
platforms = wtforms.SelectField('Platforms', choices=platform_options, coerce=str, validators=[DataRequired()])
views.py
#app.route('/', methods=['POST', 'GET'])
def index():
form = forms.PlatformForm()
if form.is_submitted():
print form.data
print request.form
if form.errors:
print form.errors
return render_template('home.html', form=form)
index.html
{% extends "base.html" %}
{% block content %}
<h4>Select a Platform</h4>
<form method="POST">
{{ form.csrf_token }}
<select class="custom-select" name="platform">
{% for value, text in form.platforms.choices %}<br>
<option value="{{ value }}">{{ text }}</option>
{% endfor %}
</select>
<button id="submit_inputs" type="submit" class="btn btn-default">Submit</button>
</form>
{% endblock %}
output
{'platforms': 'None'}
ImmutableMultiDict([('platform', u'test')])
{'platforms': [u'Not a valid choice']}
EDIT:
I figured out the problem. It's the way I'm creating the Select drop down through HTML and Jinja. Iterating through the choices and creating option tags doesn't seem to instantiate anything in the form data itself when passed back into Python. Changing that whole for loop to just
{{form.platforms}}
created a select drop down field that actually works.
You have a name mismatch. In the form, you named your select field platforms (plural). In the HTML, you use platform (singular).
I recommend that instead of manually rendering the fields in your template, you let WTForms generate the HTML for you. For the form label, you can use {{ form.platforms.label }}, and for the actual field {{ form.platforms() }}. You can pass any attributes you want to field to have as keyword arguments.
I think something might be going wrong because of the way you are rendering the form in your html file. If my hunch is right, try this:
{% extends "base.html" %}
{% block content %}
<h4>Select a Platform</h4>
<form method="POST">
{{ form.hidden_tag() }}
Select: {{ form.plaforms}}
{{ form.submit(class="btn btn-default") }}
</form>
{% endblock %}
and then try if form.validate_on_submit() in your views.py file
taken from this stack overflow answer by pjcunningham:
"validate_on_submit() is a shortcut for is_submitted() and validate().
From the source code, line 89, is_submitted() returns True if the form
submitted is an active request and the method is POST, PUT, PATCH, or
DELETE.
Generally speaking, it is used when a route can accept both GET and
POST methods and you want to validate only on a POST request."

Can I build my form without using Django form?

I'm using Django and I just did a big form Using HTML5 and bootstrap. Can I still send the form via the post method to django if I'm not using it to generate the form? Should I definitely redo my form using Django?
NOTE: There may be a better way of doing this, if there is I'd really like to know, this is just how I have done it in the past.
You will still need a forms.py file in your app.
In forms.py:
from django import forms
class MyForm(forms.Form):
# FORM FIELDS HERE
Then put the form in the context dictionary for your view:
def myView(request):
if request.method == "POST":
# FORM PROCESSING HERE
else:
myform = MyForm() #create empty form
return render(request, "template.html", {"myform": myForm}
Now in your template you can add:
<form id="myForm" name="myFormName" method="post" action=".">
{% csrf_token %}
{% for field in myform %}
{{ field.as_hidden }}
{% endfor %}
</form>
This will add your django form to the page without displaying it. All of your form inputs are given the id id_fieldName where fieldName is the field name you defined in the forms.py file.
Now when the user clicks your "submit" button (which I am assuming is a bootstrap button given the rest of your form is). You can use Jquery to input the bootstrap field values into those of the hidden form.
Something like:
$("#mySubmitButton").click(function() {
$("#id_djangoFormField").val($("#myBootstrapFormField").val());
$("#myForm").submit();
}
);
This will submit the django form with the inputs from bootstrap. This can be processed in the view as normal using cleaned_data["fieldName"].
A bit late I post the solution I found for including a form in a modal in a class based detail view. Dunno if it's really orthodox but it works.
I don't use any Form Class or Model. (Django 3.9)
Within the template, I send a field value of my object in a hidden div. If this value is missing for a special action (because for the most of actions on the object, it's not required), a modal pops asking for updating the given field. This modal is triggered with JS that check the presence (or not) of the required value.
In the modal, I display a list of radio choices buttons in an ordinary form inviting the user to update the field. The form's action leads to a view that will update the given field.
modal.html
<form action="{% url 'update-sku-column' object.pk %}" method="post">
{% csrf_token %}
{% if csv_headers %}
<div class="m-3 ps-3">
{% for header in csv_headers %}
{% for csv_sample in csv_samples %}
{% if forloop.counter0 == forloop.parentloop.counter0 %}
<div class="form-check">
<input class="form-check-input" type="radio" name="chosen-field" value="{{ forloop.counter0 }}">
<label class="form-check-label" for="{{ forloop.counter0 }}">
<span class="ms-3">{{ header }} </span>: <span class="ms-1 text-secondary">{{ csv_sample }}</span>
</label>
</div>
{% endif %}
{% endfor %}
{% endfor %}
</div>
{% endif %}
<div class="modal-footer">
<button type="submit" class="btn btn-success">Enregistrer</button>
</div>
</form>
urls.py
[...]
path('flow/<int:pk>/update-sku-column',
set_sku_column, name='update-sku-column'),
[...]
views.py
#login_required
def set_sku_column(request, pk):
if request.method == 'POST':
column = request.POST['chosen-field']
flow = Flow.objects.get(pk=pk)
flow.fl_ref_index = column
flow.save()
return redirect('mappings-list', pk=pk)
[...]
Even if I can imagine it's not the best way, it works.
don't forget the {% csrf_token %}otherwise it won't

Error Page Not Found when I update records in django

I am new with django and I try to create a simple form to update some records.
models.py
class ConfigForm(forms.ModelForm):
def __init__(self,idprov,*args,**kwargs):
super(ConfigForm,self).__init__(*args,**kwargs)
self.id_proveedor = idprov
class Meta:
model = Config
views.py
#csrf_exempt
def configView(request):
pk = request.POST.get('idprov')
prov = get_object_or_404(Config, id_proveedor=pk)
if request.method == 'POST':
form = ConfigForm(request.POST, instance = prov)
if form.is_valid():
form.save()
else:
form = ConfigForm(Request.POST, instance = prov )
return render_to_response('config.html',{'form':form},RequestContext(request))
My updateform.html
{% extends 'base.html' %}
{% block content %}
<form method='POST' action='' class='form'>
<div class="form-group">
{% csrf_token %}
{{ form.as_p }}
</div>
<button type='submit' class="btn btn-primary">Grabar</button>
</form
{% endblock %}
I pass the id from other form and works fine.
But when I press the button save the next error is displayed:
Page not found (404) Request Method: POST Request URL: http://127.0.0.1:8080/config/
No Config matches the given query.
I don't know where is the error.
The error only appear when I try to save the changes
Help please
Thanks in advance
The 404 page comes from this line:
get_object_or_404(Config, id_proveedor=pk)
The documentation states that
Calls get() on a given model manager, but it raises Http404 instead of the model’s DoesNotExist exception.
You're getting the 404 because you don't have a matching model.

Categories