Render django.forms.fields.ChoiceField object - django

In my Django Project I have the following Problem:
I would like to have a dynamic Django form. In the first step the user is asked something by the first form. When I get the postmethod the variables should be used for genereating a new form
my views.py
def calc(request):
if request.method =="POST":
get_form = CalculationForm(request.POST)
if get_form.is_valid():
op = get_form.cleaned_data['op']
ab = get_form.cleaned_data['ab']
alternative = AlternativForm(optype = op, wsgroup = ab)
return render(request, 'calculated_lensar.html', {"alternativ" : alternativ})
else:
form = CalculationForm()
return render(request, 'calc.html', {'form': form})
The secondform (postmethod) looks like
class AlternativForm(forms.Form):
praep_button = ((3, 'hallo'), (4, 'tschüss'))
def __init__(self, optype, wsgroup, *args, **kwargs):
super(AlternativForm, self).__init__(*args, **kwargs) #dont know for what this is standing
self.optype = optype
self.wsgroup = wsgroup
self.values = self.read_db()
self.praep_button = self.buttons()
self.felder = self.blub()
self.neu2 = self.myfield_choices()
def read_db(self):
import sqlite3
....
return result #tuple with 15x5 elements
def buttons(self):
praep_button = []
for i in self.values:
praep_button.append((i[4], i[1]))
return praep_button #Just formating result from read_db in tuple(15x2)
def blub(self):
return forms.ChoiceField(widget=forms.RadioSelect, choices=self.praep_button)
myfield = forms.ChoiceField(widget=forms.RadioSelect, choices=praep_button) #print --><django.forms.fields.ChoiceField object at 0x751f9b90>
def myfield_choices(self):
field = self['myfield']
"""i think here is the problem.
Above 'myfield' is a django.forms.fields.ChoiceField object, but here it is rendered to html (like it should be). I have the code from https://stackoverflow.com/questions/6766994/in-a-django-form-how-do-i-render-a-radio-button-so-that-the-choices-are-separat.
But instead i should use field = self.felder (radioselect woth tuple of the db)"""
widget = field.field.widget
attrs = {}
auto_id = field.auto_id
if auto_id and 'id' not in widget.attrs:
attrs['id'] = auto_id
name = field.html_name
return widget.render(name, field.value(), attrs=attrs)
#return widget.get_renderer(name, field.value(), attrs=attrs)
So all in all I hope the problem is clear.
If i am using AlternativForm() i get the constant form. Instead i would like to get a dynamic form. If I access in views.py:
alternative = AlternativForm(optype = op, wsgroup = ab)
alternative = alternativ.felder
than I get . Can I render that to html?
If I set in forms.py:
field = self.felder
than I get the error that it is a field and not a widget
Thank you for reading!

You just need to assign the choices in the form's __init__() method. Almost what you're doing, but instead of defining self.felder to be a field, you need to use the already initialised form's fields:
myfield = forms.ChoiceField(widget=forms.RadioSelect, choices=praep_button)
def __init__(self, optype, wsgroup, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['myfield'].choices = self.get_choices(optype, wsgroup) # create your choices in this method
def get_choices(optype, wsgroup):
# call your other methods here
return praep_button

Related

Django form class and view class connected

Hi in my code(not written by me) i have django form class and views class. I dont know how this is connected each other. Can anyone tell me how this is connected? Also can any one please tell me how this messege : Credential is in use by {0} collections that are turned on and "
"{1} collections that are turned off. Be mindful that over-using " "credentials may result in collecting being rate limited by the " "social media API is displayed, i mean if i need to change the alignment of this text where i should change?
My code classes are :
from forms.py :
class CollectionTwitterSearch2Form(BaseCollectionForm):
incremental = forms.BooleanField(initial=True, required=False, label=INCREMENTAL_LABEL, help_text=INCREMENTAL_HELP)
def __init__(self, *args, **kwargs):
super(CollectionTwitterSearch2Form, self).__init__(*args, **kwargs)
self.helper.layout[0][5].extend(('incremental',))
if self.instance and self.instance.harvest_options:
harvest_options = json.loads(self.instance.harvest_options)
if "incremental" in harvest_options:
self.fields['incremental'].initial = harvest_options["incremental"]
def save(self, commit=True):
m = super(CollectionTwitterSearch2Form, self).save(commit=False)
m.harvest_type = Collection.TWITTER_SEARCH_2
harvest_options = {
"incremental": self.cleaned_data["incremental"],
}
m.harvest_options = json.dumps(harvest_options, sort_keys=True)
m.save()
return m
from views.py :
def _get_credential_use_map(credentials, harvest_type):
credential_use_map = {}
if harvest_type in Collection.RATE_LIMITED_HARVEST_TYPES:
for credential in credentials:
active_collections = 0
inactive_collections = 0
for collection in credential.collections.all():
if collection.is_on:
active_collections += 1
else:
inactive_collections += 1
if active_collections == 0 and inactive_collections == 0:
credential_use_map[credential.id] = ("", "")
else:
credential_use_map[credential.id] = ("warning",
"Credential is in use by {0} collections that are turned on and "
"{1} collections that are turned off. Be mindful that over-using "
"credentials may result in collecting being rate limited by the "
"social media API.".format(active_collections,
inactive_collections))
return credential_use_map
class CollectionCreateView(LoginRequiredMixin, CollectionSetOrSuperuserPermissionMixin, SuccessMessageMixin,
CreateView):
model = Collection
template_name = 'ui/collection_create.html'
def get_initial(self):
initial = super(CollectionCreateView, self).get_initial()
initial["collection_set"] = CollectionSet.objects.get(pk=self.kwargs["collection_set_pk"])
return initial
def get_context_data(self, **kwargs):
context = super(CollectionCreateView, self).get_context_data(**kwargs)
context["collection_set"] = CollectionSet.objects.get(pk=self.kwargs["collection_set_pk"])
harvest_type = self.kwargs["harvest_type"]
context["harvest_type_name"] = _get_harvest_type_name(harvest_type)
credentials = _get_credential_list(self.kwargs["collection_set_pk"], harvest_type)
context["credentials"] = credentials
context["credential_use_map"] = _get_credential_use_map(credentials, harvest_type)
context["platform"] = Collection.HARVEST_TYPES_TO_PLATFORM[self.kwargs["harvest_type"]]
return context
def get_form_kwargs(self):
kwargs = super(CollectionCreateView, self).get_form_kwargs()
kwargs["coll"] = self.kwargs["collection_set_pk"]
kwargs['credential_list'] = _get_credential_list(self.kwargs["collection_set_pk"], self.kwargs["harvest_type"])
return kwargs
def get_form_class(self):
return getattr(forms, _get_collection_form_class(self.kwargs["harvest_type"]))
def get_success_url(self):
return reverse('collection_detail', args=(self.object.pk,))
def get_success_message(self, cleaned_data):
if self.object.required_seed_count() != 0:
return "New collection added. You can now add seeds."
return "New collection added."
Full code is here in this git : https://github.com/gwu-libraries/sfm-ui/tree/master/sfm/ui
It would be great anyone can explain how these two classes and template is connected and how the messege is displayed
The CollectionCreateView class is conected to the Form using the function get_form_class, this function is called by default by the CreateView, in there you can see is calling _get_collection_form_class() and as an argument is passing self.kwargs['harvest_type'] this kwargs is comming from the url declaration. The _get_collection_form_class function is returning the CollectionTwitterSearch2Form when the harvest_type is something like TwitterSearch2. The template is given by the template_name = 'ui/collection_create.html' again this is the default vehaviour. And finally for the message this is using SuccessMessageMixin.

not able to save data in django form

I am getting error Cannot assign "'1'": "dropdown.drp1" must be a "basedrop" instance. I am sharing my code. Kindly help. I got some solutions on stack but I did not understand how to implement that in my case. Django error. Cannot assign must be an instance
models.py
class basedrop(models.Model):
name = models.CharField(max_length=50,blank=False,null=False)
def __str__(self):
return self.name
class subdrop(models.Model):
name = models.CharField(max_length=100,blank=False,null=False)
bsdrop = models.ForeignKey(basedrop,null=False,blank=False,on_delete=models.CASCADE)
def __str__(self):
return self.name
class lastdrop(models.Model):
name = models.CharField(max_length=100,blank=False,null=False)
sbdrop = models.ForeignKey(subdrop,null=False,blank=False,on_delete=models.CASCADE)
def __str__(self):
return self.name
class dropdown(models.Model):
name = models.CharField(max_length=50)
drp1 = models.ForeignKey(basedrop,max_length=50,on_delete=models.CASCADE)
drp2 = models.ForeignKey(subdrop,max_length=50,on_delete=models.CASCADE)
drp3 = models.ForeignKey(lastdrop,max_length=50,on_delete=models.CASCADE)
def __str__(self):
return self.name
views.py
def create_drop(request):
if request.method == 'POST':
form = dropdownForm(request.POST or None)
if form.is_valid():
form = dropdown(name=request.POST.get('name'),drp1_Id=int(request.POST.get('drp1')),
drp2_Id=int(request.POST.get('drp2')),drp3_Id=int(request.POST.get('drp3')))
form.save()
return HttpResponse('<p>this is working</p>')
form = dropdownForm()
return render(request,'drop.html',{'form':form})
forms.py
class dropdownForm(forms.ModelForm):
drp1 = forms.ChoiceField(choices=((bs.get('id'),bs.get('name')) for bs in basedrop.objects.all().values('id','name')))
class Meta:
model = dropdown
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['drp2'].queryset = subdrop.objects.none()
self.fields['drp3'].queryset = lastdrop.objects.none()
if 'drp1' in self.data:
try:
country_id = int(self.data.get('drp1'))
self.fields['drp2'].queryset = subdrop.objects.filter(id=country_id).order_by('name')
except (ValueError, TypeError):
pass
elif 'drp2' in self.data:
try:
country_id = int(self.data.get('drp2'))
self.fields['drp3'].queryset = lastdrop.objects.filter(id=country_id).order_by('name')
except (ValueError, TypeError):
pass
elif self.instance.pk:
self.fields['drp2'].queryset = self.instance.drp1.city_set.order_by('name')
self.fields['drp3'].queryset = self.instance.drp2.city_set.order_by('name')
I don't know if it could cause failures but you're passing the POSTed argument 'drp1' as integer for drp1_Id, drp2_Id and drp3_Id.
You'd have it much easier if you choose a more intuitive coding style.
For example this line:
form = dropdown(name=request.POST.get('name'), drp1_Id=int(request.POST.get('drp1')), drp2_Id=int(request.POST.get('drp1')), drp3_Id=int(request.POST.get('drp1')))
If you get the objects and pass them to the dropdown you gain readability specially if there is an error:
drp1_pk = request.POST.get('drp1')
drp1 = basedrop.objects.get(pk=drp1_pk)
drp2 = subdrop.objects.get(pk=drp1_pk)
drp3 = lastdrop.objects.get(pk=drp1_pk)
form = dropdown(name=request.POST.get('name'), drp1=drp1, drp2=drp2, drp3=drp3)
But again:
It looks strange to pass the same primary key to three different models.

How to set Django form initial value only one field?

forms.py
class ExForm(forms.Form):
a = forms.CharField(max_length=100)
b = forms.ChoiceField(choices=SOME_CHOICES)
c = forms.ChoiceField(choices=SOME_CHOICES)
def __init__(self, request, *args, **kwargs):
super(ExForm, self).__init__(*args, **kwargs)
self.initial['a'] = 'something value'
views.py
def view(request):
form = ExForm(request.GET or None)
return render(request, 'a.html', {'form': form})
I want to set an initial value to 'a' field only.
When I submit this form, b and c fields values not set in the form from request.GET.
It works.
def __init__(self, request, *args, **kwargs):
super(ExForm, self).__init__(*args, **kwargs)
self.initial['a'] = 'something value'
self.initial['b'] = request.b
self.initial['c'] = request.c
I want to know how to set initial value only one field.
Do I set all field initial values?
You can use initial field's argument:
class ExForm(forms.Form):
a = forms.CharField(max_length=100, initial='Some value')
b = forms.ChoiceField(choices=SOME_CHOICES)
c = forms.ChoiceField(choices=SOME_CHOICES)
Yes, you can specify a default value to a particular FormField, you can specify it using initial:
class ExForm(forms.Form):
a = forms.CharField(max_length=100, initial="Any Value")
b = forms.ChoiceField(choices=SOME_CHOICES)
c = forms.ChoiceField(choices=SOME_CHOICES)
...
Or specifying a default value from choices, use default='Some Value'
SOME_CHOICES = [
('1','Value1')
('2','Value2')
]
class ExForm(forms.Form):
a = forms.CharField(max_length=100, initial="Any Value")
b = forms.ChoiceField(choices=SOME_CHOICES, default='1')
c = forms.ChoiceField(choices=SOME_CHOICES, default='2')
...
Hope it clears your doubt.

Access missing value in form.cleaned_data

I was trying to dynamically generate fields as shown in http://jacobian.org/writing/dynamic-form-generation/. My case slightly differs in that I am looking to use multiplechoicefield that is dynamically created. This is what I came up with...
views.py
def browseget(request):
success = False
if request.method == 'POST':
list_form = ListForm(request.POST)
if list_form.is_valid():
success = True
path = list_form.cleaned_data['path']
minimum_size = list_form.cleaned_data['minimum_size']
follow_link = list_form.cleaned_data['follow_link']
checkboxes = list_form.cleaned_data['checkboxes']
....do something
else:
list_form = ListForm(name_list)
ctx = {'success': success, 'list_form': list_form, 'path': path, 'minimum_size': minimum_size}
return render_to_response('photoget/browseget.html', ctx, context_instance=RequestContext(request))
forms.py
class ListForm(forms.Form):
path = forms.CharField(required=False)
minimum_size = forms.ChoiceField(choices=size_choices)
follow_link = forms.BooleanField(required=False, initial=True)
def __init__(self, *args, **kwargs):
name_list = kwargs.pop('name_list', None)
super(ListForm, self).__init__(*args, **kwargs)
print 'Received data:', self.data
if name_list:
name_choices = [(u, u) for u in name_list]
self.fields['checkboxes'] = forms.MultipleChoiceField(required=False, label='Select Name(s):', widget=forms.CheckboxSelectMultiple(), choices=name_choices)
def clean_path(self):
cd = self.cleaned_data
path = cd.get('path')
if path == '': path = None
return path
def clean_minimum_size(self):
cd = self.cleaned_data
minimum_size = cd.get('minimum_size')
if minimum_size is None: minimum_size = 0
return int(minimum_size)
The form generates and displays perfectly... until I post some data. The 'checkboxes' field doesn't show up in list_form.cleaned_data.items() while it shows in self.data. As it is the form breaks with a KeyError exception. So Im asking, how do i access the checkboxes data?
You're not passing in the name_list parameter when you re-instantiate the form on POST, so the field is not created because if name_list is False.

Django How to work with MultipleChoiceField

form.py:
CHECKBOX_CHOICES = (
('Value1','Value1'),
('Value2','Value2'),
)
class EditProfileForm(ModelForm):
interest = forms.MultipleChoiceField(required=False,
widget=CheckboxSelectMultiple(),
choices=CHECKBOX_CHOICES,)
def save(self, *args, **kwargs):
u = self.instance.user
u.interest = self.cleaned_data['interest']
u.save()
profile = super(EditProfileForm, self).save(*args,**kwargs)
return profile
it saves in db as [u'value1', u'value2']
Now, How can I only render in my template to show as string like value1, value2 without [u' '] or is there a better way to save the value as a string?
u.interest = u','.join(self.cleaned_data['interest'])