I'm trying to display forms for my project using CheckboxSelectMultiple, but form displays nothing
This is my forms.py
class ItemForExhibitionForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.artist_id = kwargs.pop('artist_id')
super(ItemForExhibitionForm, self).__init__(*args, **kwargs)
self.fields['name'].queryset = Item.objects.all()
class Meta:
model = Item
fields = ['name',]
widgets = {'name' : forms.CheckboxSelectMultiple()}
And it is my views.py
else: #GET
form = ExhibitionEntryForm()
artist_id = Artist.objects.get(user_id = request.user.id).id
form2 = ItemForExhibitionForm(artist_id = artist_id)
return render(request, 'exhibition_entry.html', {'form' : form, 'form2' : form2})
result
how to display form checkbox?
i am sure, you are forget in template render form.media
https://docs.djangoproject.com/en/4.1/topics/forms/media/
CheckboxSelectMultiple use js to create own widget.
in your template before form render add:
<-- in your html template -->
{{ form.media }}
<form >
{{ form.as_p}}
</ form>
Related
Im trying to add a field called, interested_fields inside my personalInfo model which users can choose from and the choices themselves come from another models' objects with the help of ManyToMany relation between the two models. Here are my models.py codes(I simplified my personal model by removing some other fields like name, age, etc in order to make it more readable for you):
class Field(models.Model):
id = models.AutoField(primary_key=True)
slug = models.CharField(max_length=16, default='default')
title = CharField(max_length=32)
class PersonalInfo(models.Model):
id = models.AutoField(primary_key=True)
interested_fields = models.ManyToManyField(Field, blank=True)
then, I created a ModelForm like this:
class InterestedFieldsForm(forms.ModelForm):
interested_fields = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple, choices=Field.objects.all(), required=False)
class Meta:
model = PersonalInfo
fields = ['interested_fields']
and created a get and post functions inside my views like this:
class PersonalView(View):
template_name = 'reg/personal.html'
def get(self, request, *args, **kwargs):
context = {}
context['fields'] = Field.objects.all()
return render(request, self.template_name, context=context)
def post(self, request, *args, **kwargs):
user = request.user
if request.method == 'POST':
form = InterestedFieldsForm(request.POST)
if form.is_valid():
profile = form.save(commit=False)
profile.user = request.user
profile.save()
else:
form = InterestedFieldsForm()
return render(request, 'reg/done.html', context={'form': form})
and finally in template, inside the form I added this for loop:
{% for field in fields %}
<label class="containerq ant-col ant-col-md-6 ant-col-xs-8" >
<span>
<input type="checkbox" name="interested_fields" {% if field.slug in user.personalInfo.interested_fields %} checked="checked" {% endif %} value="{{field.title}}">
<span style="margin-left:7px" class="checkmark"></span>
</span>
<span>{{field.title}}</span>
</label>
{% endfor %}
when I submit the form it gives me this error:
cannot unpack non-iterable Field object
Im new to django so I really dont know what am I doing wrong. thank you for your answers
You should use a ModelMultipleChoiceField
interested_fields = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple, queryset=Field.objects.all(), required=False).
I want to be able to vary the placeholder like so:
<input placeholder=" {{ input.placeholder }}">
Where input is a model with the "placeholder" field. The placeholder field will vary since I'll be using a formset, and each placeholder will vary.
Here's my modelForm
class Value(forms.ModelForm):
class Meta:
model = ValueModel
fields = ['value_text']
widgets = {
'value_text': forms.TextInput(attrs={'class': 'form-control'})
and my modelformset
values_formset = modelformset_factory(model=ValueModel, extra=0, form=Value)
I've tried
class Value(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(Value, self).__init__(*args, **kwargs)
self.fields['value_text'].widget.attrs['placeholder'] = self.fields['placeholder']
class Meta:
model = ValueModel
fields = ['value_text', 'placeholder']
widgets = {
'value_text': forms.TextInput(attrs={'class': 'form-control'})
And other attempts at trying to modify the self.fields with no success.
Edit: The relevant part of my views.py:
def page_view(request, values_id):
values_form = values_formset(queryset=ValueModel.objects.filter(
values_id=values_id))
context = {'value': values_form}
return render(request, 'view.html', context)
My template view:
{{ value.management_form }}
{% for form in value %}
{{ form.id }}
{{ form.value_text }}
{% endfor %}
self.fields['placeholder'] refers to a form field object, not a value; you couldn't use it as a placeholder. But it seems like what you want is to use the value of the model instance.
def __init__(self, *args, **kwargs):
super(Value, self).__init__(*args, **kwargs)
self.fields['value_text'].widget.attrs['placeholder'] = self.instance.placeholder
I have a website where user have 2 model for their profile, user_detail and user_location. I tried to serve 2 model form on one page with one submit. The problem is when the data from those model form does not save in to the database.
I confirmed that self.request.POST in the post method returns the correct data.
I tried :
Django ModelForm not saving data to database - Does not work
Django ModelForm not saving data - Does not work
The following code if for admins.
Here is my view :
class UpdateProfile(LoginRequiredMixin, UpdateView):
template_name = 'account/user_profile.html'
fields = '__all__'
model = models.UserProfile
user_detail_form_class = forms.UserDetailForm
user_location_form_class = forms.UserLocationForm
def get_context_data(self, **kwargs):
user_profile = get_object_or_404(models.UserProfile, pk=self.kwargs.get(self.pk_url_kwarg))
context = super(UpdateProfile, self).get_context_data(**kwargs)
if 'user_detail_form' not in context:
context['user_detail_form'] = self.user_detail_form_class(instance=user_profile.user_detail)
if 'user_location_form' not in context:
context['user_location_form'] = self.user_location_form_class(instance=user_profile.user_location)
return context
def get(self, request, *args, **kwargs):
super(UpdateProfile, self).get(request, *args, **kwargs)
return self.render_to_response(self.get_context_data())
def post(self, request, *args, **kwargs):
user_detail_form = self.user_detail_form_class(request.POST)
user_location_form = self.user_location_form_class(request.POST)
if user_detail_form.is_valid() and user_location_form.is_valid():
user_detail_form.save()
user_location_form.save()
return redirect(self.get_success_url())
else:
return self.render_to_response(self.get_context_data())
def get_success_url(self):
return reverse('account:admin_client_list')
def dispatch(self, request, *args, **kwargs):
if not request.user.groups.filter(name__in=['Admin']).exists():
return errors.render_403(request)
return super(UpdateProfile, self).dispatch(request, *args, **kwargs)
Here is my template :
{% extends 'base.html' %}
{% block content %}
<form method='POST' action="">{% csrf_token %}
{{ user_detail_form }}
{{ user_location_form }}
<input type="submit" value="Submit">
</form>
{% endblock %}
Here is the form :
class UserDetailForm(forms.ModelForm):
class Meta:
model = models.UserDetail
fields = '__all__'
class UserLocationForm(forms.ModelForm):
class Meta:
model = models.UserLocation
fields = '__all__'
You need to pass the instance parameter when you are creating the ModelForm in the post method. Sample code:
user_profile = get_object_or_404(models.UserProfile, pk=self.kwargs.get(self.pk_url_kwarg))
user_detail_form = self.user_detail_form_class(request.POST, instance=user_profile.user_detail)
user_location_form = self.user_location_form_class(request.POST, instance=user_profile.user_location)
I have the detail view of "part" in views.py
class part_detail_view(DetailView):
model = part_list
context_object_name = 'part_detail'
template_name = 'part_detail.html'
def get_context_data(self, **kwargs):
context = super(part_detail_view, self).get_context_data(**kwargs)
context['my_list'] = populate_nav_bar()
return context
but inside this URL I also want to display another form "CreateView" of the stock model so that from the same page I can display the form to add stock of the part and add the stock. This was done easily in function based view but I am not sure how to do this in class based view.
You must create your form explicitly in forms.py:
# forms.py
class ParForm(forms.ModelForm):
class Meta:
model = Part # Your Part model
fields = '__all__'
Then just inject the form into the context in get_context_data():
# views.py
class PartDetailView(DetailView):
...
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['part_form'] = PartForm() # Your part form
return context
Then render the form in template:
...
<form method="post" action="{% url 'create_part' %}">
{{ part_form }}
<button type="submit">Submit</button>
</form>
...
where create_part is the url of your CreateView.
When I read the documentation about modelforms and widgets it looks like you can use any widget on any modelform but that there are certain default widgets used for form fields corresponding to modelform fields. I'm able to render a radio input using a form field but not with a modelform field.
I have tried many different things, but I just can't seem to render a RadioSelect widget of a modelform field which comes from a model field. Is this even possible?
Btw, my goal is to let the initial value of the radio input correspond with the current value of the model field(A boolean).
Attempt 1:
# views.py
class SettingsView(FormView):
template_name = 'settings.html'
success_url = 'settings/saved/'
form_class = NicknameForm
def post(self, request, *args, **kwargs):
profile = request.user.get_profile()
if request.POST['show_nickname'] == 'False':
profile.show_nickname = False
profile.save()
elif request.POST['show_nickname'] == 'True':
profile.show_nickname = True
profile.save()
return super(NicknameFormView, self).post(request, *args, **kwargs)
def get_context_data(self, **kwargs):
"""
To be able to use 'show_nickname_form' instead of plain 'form' in the template.
"""
context = super(NicknameFormView, self).get_context_data(**kwargs)
context["show_nickname_form"] = context.get('form')
return context
# models.py
from django.db import models
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.OneToOneField(User,
unique=True,
verbose_name='user',
related_name='profile')
show_nickname = models.BooleanField(default=True)
# forms.py
from django import forms
from models import Profile
CHOICES = (('shows_nickname', 'Yes'), ('hides_nickname', 'No'))
class NicknameForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('show_nickname',)
widgets = {
'show_nickname': forms.RadioSelect(attrs={'choices': CHOICES}),
}
Part from my template:
<form action='' method="post">
{{ show_nickname_form.as_ul }} {% csrf_token %}
<input type="submit" value="Save setttings">
</form>
The form that is rendered from {{ show_nickname_form.as_ul }}:
<li><label for="id_show_nickname_0">show nickname:</label>
<ul></ul>
</li>
<div style='display:none'><input type='hidden' name='csrfmiddlewaretoken' value='1BqD6HJbP5e01NVwLtmFBqhhu3Y1fiOw' /></div>`
Attempt 2:
# forms.py
from django import forms
from models import Profile
class NicknameForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('show_nickname',)
widgets = {
'show_nickname': forms.RadioSelect(),
}
Attempt 3
# forms.py
CHOICES = ((True, 'On',),
(False, 'Off',))
class NicknameForm(ModelForm):
show_nickname = ChoiceField(widget=RadioSelect, choices=CHOICES, initial=True , label='')
class Meta:
model = Profile
fields = ('show_nickname',)
This renders the radio input fine but I need it to take the initial value of the corresponding model field show_nickname instead of the constant True.
I am using Django 1.4 btw.
You need to make it into a ChoiceField instead of a BooleanField with a choice for each and a RadioWidget in order for it to display radio buttons.
https://docs.djangoproject.com/en/dev/ref/forms/fields/#django.forms.ChoiceField
If you want to keep the boolean field, you will most likely have to do some hacking to create your own field/widget.
# views.py
class SettingsView(FormView):
template_name = 'settings.html'
success_url = 'settings/saved/'
form_class = NicknameForm
def get_form(self, form_class):
"""
Returns an instance of the form to be used in this view.
"""
form = super(SettingsView, self).get_form(form_class)
if 'show_nickname' in form.fields:
profile = self.request.user.get_profile()
form.fields['show_nickname'].initial = profile.show_nickname
return form
def post(self, request, *args, **kwargs):
profile = request.user.get_profile()
if request.POST['show_nickname'] == 'False':
profile.show_nickname = False
profile.save()
elif request.POST['show_nickname'] == 'True':
profile.show_nickname = True
profile.save()
return super(NicknameFormView, self).post(request, *args, **kwargs)
def get_context_data(self, **kwargs):
"""
To be able to use 'show_nickname_form' instead of plain 'form' in the template.
"""
context = super(NicknameFormView, self).get_context_data(**kwargs)
context["show_nickname_form"] = context.get('form')
return context