Unable to render ChoiceField on template in Django - python

I'm trying to show a ChoiceField in a template on Django but I'm unable to make it work.
I have found some solutions here, but seems not work to me (Possible solution), but I get the error: too many values to unpack on line {{ form.as_p }}.
So searching on the web, I've found this Solution but I'm not able to addapt to my code and make it works. I'm getting an TextField instead a "Dropdown" (in Django Choicefield). And also, this solution list all items on a for loop and I get 4 textfields, instead 2 Choicefields with the elements.
My forms.py looks like:
class SimpleDeploy(forms.Form):
def __init__(self, networkList, policiesList, *args, **kwargs):
super(SimpleDeploy, self).__init__(*args, **kwargs)
if networkList and policiesList:
self.fields['networkPartitions'] = forms.ChoiceField(choices=networkList)
self.fields['applicationPolicies'] = forms.ChoiceField(choices=policiesList)
else:
self.fields['networkPartitions'] = forms.ChoiceField(choices='No network partitions found')
self.fields['applicationPolicies'] = forms.ChoiceField(choices='No application policies found')
And on my views.py:
def simpleDeploy(request):
netList = getDetailsNetworkPartitions(request)
polList = getDetailsApplicationPolicies(request)
if request.method == 'POST':
abs(5) #Nothing here by the moment
else:
simpleForm = SimpleDeploy(networkList=netList, policiesList=polList)
return render(request, 'apacheStratos/simpleDeploy.html', {'form': simpleForm})
Where netList and polList are list of tuples like:
[(u'application-policy-2', u'application-policy-2'), (u'application-policy-1', u'application-policy-1')]
And on my template, I'm trying to show the ChoiceField like:
<table class="table">
{% for item in form.networkPartitions.field.choices %}
<label for="">Network Partitions</label> <input type="choicefield" name="networkPartitions" value="{{item.1}}"/>
{% endfor %}
{% for item in form.applicationPolicies.field.choices %}
<label for="">Application Policies</label> <input type="choicefield" name="applicationPolicies" value="{{item.1}}"/>
{% endfor %}
</table>
How can I get the choicefield and access to the elements without using a for loop? What I'm doing wrong?
Thanks.

Thanks to #raphv, the solution was put {{form.networkPartitions}} and {{form.applicationPolicies}} on the template. So simple....

Related

What would be the best approch to display a commenting form in the ListView for each blog post?

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 %}

Unable to select value in action intermediate page

I have two models User and Group.
I'm implementing an action "Change Groups" in UsersAdmin that redirects to an intermediate page with 2 MultipleChoiceFields for Groups, that I want to be used to either remove users from certain groups, add users to other groups, or do both in one go (i.e. move them).
The docs are very short about this subject, so in order to do this, I'm following this article.
Here's my form:
class ChangeUsersGroupsForm(forms.Form):
_selected_action = forms.CharField(widget=forms.MultipleHiddenInput)
from_groups = forms.ModelMultipleChoiceField(Group.objects, required=False)
to_groups = forms.ModelMultipleChoiceField(Group.objects, required=False)
My admin action:
def change_groups_action(self, request, queryset):
if 'apply' in request.POST:
from_groups = request.POST["from_groups"]
to_groups = request.POST["to_groups"]
from_groups_qs = Group.objects.filter(pk__in=from_groups).all()
to_groups_qs = Group.objects.filter(pk__in=to_groups).all()
user_ids = [u.user_id for u in queryset]
# task that will do the job of actually moving the users
change_users_groups.delay(from_groups_qs, to_groups_qs)
self.message_user(request, "Changed groups of %s users" % len(user_ids))
return HttpResponseRedirect(request.get_full_path())
form = ChangeUsersGroupsForm(initial={'_selected_action': queryset.values_list('id', flat=True)})
return render(request, "admin/change_users_groups.html", {'queryset': queryset, 'form': form})
change_groups_action.short_description = "Change Groups"
Here's my template:
<!-- users/templates/admin/change_users_groups.html -->
{% extends "admin/base_site.html" %} {% block content %}
<form action="" method="post">
{% csrf_token %}
{{ form }}
<br />
<br />
<p>The Group changes will be applied to the following users:</p>
<ul>
{{ queryset|unordered_list }}
</ul>
<input type="hidden" name="action" value="change_groups_action" />
<input type="submit" name="apply" value="Confirm" />
</form>
{% endblock %}
This is how the intermediate page renders:
First (but minor) issue is that the form fields are displayed in a row, instead of each in one row. But let's skip that for now.
The big issue is that when I select a Group, nothing happens, the Group doesn't seem to be selected.
Instead I see the following error on the browser Console:
Uncaught TypeError: django.jQuery is not a function
This error is printed every time I click on an option.
Anyone knows what's going on?
Django 2.2
Python 3.8.10
I've had this problem before, but in different situation (unrelated to Django admin). I almost always turned out to be because JQuery was not loaded or it was loaded too late in the template.
According to Django documentation:
If you want to use jQuery in your own admin JavaScript without
including a second copy, you can use the django.jQuery object on
changelist and add/edit views. Also, your own admin forms or widgets
depending on django.jQuery must specify js=['admin/js/jquery.init.js',
…] when declaring form media assets.
So that would make your form class look like:
class ChangeUsersGroupsForm(forms.Form):
_selected_action = forms.CharField(widget=forms.MultipleHiddenInput)
from_groups = forms.ModelMultipleChoiceField(Group.objects, required=False)
to_groups = forms.ModelMultipleChoiceField(Group.objects, required=False)
class Media:
js = ['admin/js/jquery.init.js']
Regarding your form field form. I suggest rendering each field separately like so:
{{ form.from_groups }}
<br/>
{{ form.to_groups }}
This seems like the simplest solution
Let me know if that helps :)

Stuck with django form validation

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.

Django Crispy forms not showing bootstrap/css or button

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/

Web server ini-file editor using django

I wish to edit ini files over web server, decided to use django, been using it for few days now. I can't figure out how to accomplish this. I have ini file structure looking like this:
{'GROUP', {PROPERTY : VALUE}}
Example when I read this kind of ini file:
[LOG]
FilePath = C:/Log
[CMD]
Level = 5
I will get my data structure filled like this:
{'LOG', {'FilePath' : 'C:/Log',},
{'CMD', {'Level', '5'}}}
Loop looks like this:
for group in settingsDict:
print group # group
for property in settingsDict[group]:
print property , # property
print settingsDict[group][property] # value
I am using ini file parser.
I am having trouble understanding how to correctly develop in django: views.py is some kind of controller for django and templates are views and model would be my ini file (probably linked with db using django model), or am I getting something wrong?
I have no problem passing this dictionary to template, making a for loop in it and creating html tags like: <input type="text" name={{ property }} value={{ value }} maxlength="100" />. But how do I then post all the edited values back to control to save them in file (or db)? I Would need all 3 values, that is GROUP, PROPERTY and VALUE.
Then I discovered django also has html widgets, which you create in views.py and then pass it to template. But this is where I stop understanding things, since I am creating widget in my controller class, but even if I am.
Shall I create a list of all django widgets and pass it to template? Same question occurs, how do I get all the widget values back to controller (views.py)?
Update (11.6.2012):
My code looks like this:
views.py
class DynForm(forms.Form):
def setFields(self, kwds):
keys = kwds.keys()
keys.sort()
for k in keys:
self.fields[k] = kwds[k]
def settings(request):
global Settings #my ini dict
kwargs = {}
for group in Settings:
for property in Settings[group]:
kwargs[property] = forms.CharField(label = property, initial = Settings[group][property])
f = DynForm()
f.setFields(kwargs)
return render_to_response('/settings.html',
{
'textWidget' : f,
})
#csrf_exempt
def save(request):
if request.method == 'POST': # If the form has been submitted...
form = DynForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
# process form data
# and return response
settings.html
<form action="/save/" method="post">
{% csrf_token %}
{% for field in textWidget %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label }}: {{ field }}
</div>
{% endfor %}
<p><input type="submit" value="Save" /></p>
</form>
The problem is, DynForm(request.POST) returns null so I can't get field values. My request.POST is correct, containing all fields and values. As much as I know, I am not suppose to parse request.POST data "by hands"?
OK, finally figured it out, taking me a lot of time (I am lacking a lot of python and django knowledge). I can't paste final solution because of copy right permissions, here is the concept:
Form
class DynamicForm(forms.Form):
def __init__(self,*k,**kw):
forms.Form.__init__(self,*k,**kw)
# loop over data from **kw
# create field
# set field default value
Notes about this code:
If form doesn't use super(SuperForm, self).__init__(*args, **kwargs), you must use forms.Form.__init__(self,*k,**kw) so you can append fields to form using self.fields attribute.
If you need to use default field value, use self.data[field] = defVal not initial = defVal. Form becomes unbound and you won't be able to parse data in your request.POST method. Unbound form (and with errors) will always return is_valid() False.
With this class, you have no problems parsing request.POST data. Looping over dynamic form fields looks like this:
View
for name,field in form.fields.items():
# name - field name
# form.data[name] - field value
Notes:
For the sake of simplisity use #csrf_exempt tag before POST method. See http://jordanmessina.com/2010/05/24/django-1-2-csrf-verification-failed/
Template code loops over fields in form displaying field label and value separated with :
Template
<form action="/Tris/save/" method="post">
{% csrf_token %}
{% for field in textWidget %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.non_field_errors }}
{{ field.label }}: {{ field }}
</div>
{% endfor %}
<p><input type="submit" value="Save" /></p>
</form>
Most of the solution is from here: http://jacobian.org/writing/dynamic-form-generation/ and django documentation.

Categories

Resources