I am working with django forms and am using django bootstrap form(https://django-bootstrap-form.readthedocs.org/en/latest/) for UI. I am able to create forms in html using the django bootstrap form. Now the problem is that i want to edit the forms and update the record in the database.
My question is how can i use the django bootstrap form to provide a form for editing
for eg:
i am using
<form role="form" action="/abc/" method="POST">{% csrf_token %}
<div class="form-group">
{{ form.name.errors }}
{{ form.name|bootstrap }}
</div>
</form>
this is the form when filling for the first time. When i click on the edit option i want the same UI but with value="the_value_saved_in_the_database" something like
{{ form.name|bootstrap value="_data_"}}
How can i achieve it?
Hope you understand the problem.
Thanks in advance
You need to load the form with data (called binding the form) before you render it. If the form represents some data that you have stored in the model, then create a ModelForm and pass in the model instance for which you want to edit the data.
Here is an example:
class AddressBook(models.Model):
name = models.CharField(max_length=200)
email = models.EmailField()
class AddressForm(forms.ModelForm):
class Meta:
model = AddressBook
def edit_address(request, pk=None):
existing_entry = AddressBook.objects.get(pk=pk)
form = AddressForm(instance=existing_entry)
return render(request, 'edit.html', {'form': form})
In urls.py:
url('^address/edit/(?P<pk>\d+)$', 'edit_address', name="edit"),
url('^address/save/$', 'save_address', name="save"),
Now, when you call your view http://localhost:8000/address/edit/1, the form will be populated by the data for the entry whose primary key is 1 ready for editing. In your template, simply render the form, and point it to the save view:
<form method="post" action="{% url 'save' %}">
{% csrf_token %}
{{ form|bootstrap }}
</form>
If you are going to be doing this often, its easier to use the generic class based views (like CreateView, EditView) to simplify your code.
Related
I currently have fully functional commenting form in my blog post view that I want to display in the ListView. Sort of like linkedin has under every list item, if you have noticed, i think facebook has the same thing.
Is there a shortcut to achieve this?
I supposed you can combine a ListView with a FormMixin (https://docs.djangoproject.com/fr/4.1/ref/class-based-views/mixins-editing/#django.views.generic.edit.ModelFormMixin)
In each item of list, you create your form html and checking if form exist and if form instance corresponds to current list view for displaying errors and data in case of invalid form sent.
class MyPostList(FormMixin, ListView);
model = Post
form = CommentAddForm
template...
class CommentAddForm(ModelForm):
class Meta:
model = Comment
fields = ('post_id', 'txt'...)
{% for post in post_list %}
{{post}}
<form>
{% if form.data.post_id == post.pk %}{{form.errors}}{% endif %}
<input type="hidden" name="post_id" value="{{post.pk}}" />
</form>
{% endfor %}
I have this view to show the previously populated data, which was only populated in the admin panel:
from .models import (Token,
Sell,
LogisticCost,
IncomeCost,
FinalPayment,
CustomerServiceCost,
Fatura)
def product_list(request):
context = {'product_list': ProductList.objects.filter(client=request.user.id).all(),
'data_payment': Fatura.objects.all()}
return render(request, 'Clientes/list_products.html', context)
This is the view to update these values:
class UpdateProduct(UpdateView):
model = ProductList
context_object_name = 'product_list'
template_name = 'Clientes/update_product.html'
fields = ['name', 'description', 'cost_price', 'sell_price', 'ncm']
My form in the update page is:
<form method="post" action="{% url 'client:product_list' %}">
{% csrf_token %}
{{ form }}
<button class="btn btn-inverse" type="submit">Atualizar</button>
</form>
My update page is working as expected, showing every value related to the selected object, but when I submit the form the model has not changed. What is happening to not update the values?
You are submitting the form to the product_list view - you should submit it to the update view instead.
Depending on your URLs, the form should look something like:
<form method="post" action="{% url 'client:update_product' product_list.pk %}">
After all, I removed the action from the form and I added the variable success_url = reverse_lazy('client:product_list') to my UpdateView. That solved the problem.
I'm trying to get validation running on a django form used to retrieve a list of objects in a ListView View. Despite having read django docs and many other questions here, I can't find out what's wrong in this simple test code:
form.html
<form action="list.html" method="get">
{{ form }}
<input type="submit" value="Submit">
</form>
list.html
<ul>
{% for area in object_list %}
<li>{{ area.name }}</li>
{% endfor %}
</ul>
forms.py
from django import forms
class SearchArea(forms.Form):
area = forms.CharField(label='Area code', max_length=6)
def clean_area(self):
area = self.cleaned_data['area'].upper()
if '2' in area:
raise forms.ValidationError("Error!")
return area
views.py
class HomePageView(FormView):
template_name = 'form.html'
form_class = SearchArea
class AreaListView(ListView):
template_name = 'list.html'
model = AreaCentral
def get_queryset(self):
q = self.request.GET.get('area')
return AreaCentral.objects.filter(area__istartswith=q)
When I try to submit something like "2e" I would expect a validation error, instead the form is submitted. Moreover I can see in the GET parameters that 'area' is not even converted to uppercase ('2E' instead of '2e').
The default a FormView will only process the form on POST; the GET is for initially displaying the empty form. So you need to use method="post" in your template form element.
Your action attribute is also suspect; it needs to point to the URL of the form view. If that actually is the URL, note it's not usual to use extensions like ".html" in Django URLs, and I would recommend not doing so.
I got crispy forms working with my model, though the form looks plain and bootstrap not showing up, also there seems to be no button. Even when adding button and clicking it(it refreshes) no data has been saved to the database. I have tried many ways. What seems to be wrong? Any help would be highly appreciated.
forms.py
class PlotForm(forms.ModelForm):
helper = FormHelper()
helper.form_tag = False
helper.form_method = 'POST'
class Meta:
model = Plot
fields = '__all__'
views:
def plot_form(request):
return render(request, 'plot_form.html', {'form': PlotForm()})
the html:
{% load crispy_forms_tags %}
<form action="" method="POST">
{% crispy form %}
<input type="submit" class="btn btn-default" value="save">
First the {% csrf_token %} is missing. Second If I remember it correct you need to use {{ form|crispy }} to load the form.
And third I would recommend to use Widget Tweaks
<form method='POST' action="/" enctype='multipart/form-data'>
{% load widget_tweaks %}
{% csrf_token %}
{{ form.first_name |add_class:"customCSS1 customCSS2" }}
{{ form.second_name |add_class:"customCSS3 customCSS4" }}
</form>
{{ form.media.js }}
with this plugin you can style the form as you wish. All Css classes work. Crispy is nice but you have get into the documentation and there are always some workarounds you need to do when you want to style the form. With Widget Tweaks you can simply apply any CSS class. When you really know your way around with crispy you can do a lot but to get to that point....
I switched at some Point and now everything works like a charm
Hope that helps if not leave a comment :)
Edit
I just saw something in your views.py. You are not referencing the form correct as far as I can tell.
from appName.forms import PlotForm
def plot_form(request):
form = PlotForm(request.POST or None, request.FILES or None) #request files is only required when you want to upload a file
if form.is_valid():
instance = form.save(commit = False)
...
instance.save()
#messages.success(request, 'form was saved') #optional
context = {
'form':form,
}
return render(request, 'AppName/plot_form.html', context)
Maybe that will do the trick. You did not have a form validation and Im not sure if the "()" at {'form': PlotForm()} would break the code.
I also faced the same issue. Solved it by testing it on firefox instead of google chrome. Apparently, Chrome does not load CSS style for a few local web apps. Got it to work after following this hack. https://css-tricks.com/new-in-chrome-css-overview/
I've built a Form Page in the admin of my Mezzanine project, but I'd like to populate a couple of the fields automatically, depending on where the click to the form has come from: it's a "feedback" form and I'd like to automatically add the ID of the object that the user is providing feedback on to a hidden field in the form.
I've copied the template code from mezzanine/forms/templates/pages/form.html to a custom template and it receives the dictionary I pass it from my view, but I can't work out to pass it my the form I want rendered. The #processor_for function receives request and page... but where's the form?
What should I be passing to my template to render the form?
You can use the template tag fields_for:
{% load mezzanine_tags %}
{% errors_for some_form_object %}
<form method="POST">
{% fields_for some_form_object %}
<input type="submit">
</form>