I have the following code
models.py
fitness_choices = (('wl', 'Weight Loss'), ('ft', 'Firming and Toning'),
('yo', 'Yoga'), ('ot', 'Others'), )
periods_to_train = (('da', 'Daily'), ('ft', 'Few Times A Week'),
('oa', 'Once A Week'), )
class Fitness(models.Model):
fitness_goals = models.CharField(max_length=80, choices=fitness_choices)
training_periods = models.CharField(max_length=5, choices=periods_to_train)
forms.py
class FitnessForm(ModelForm):
fitness_goals = forms.MultipleChoiceField(
choices=fitness_choices, widget=forms.CheckboxSelectMultiple)
training_periods = forms.MultipleChoiceField(
choices=DAYS_OF_WEEK, widget=forms.CheckboxSelectMultiple)
class Meta:
model = Fitness
views.py
from apps.services.forms import FitnessForm
def fitness(request):
""" Creating a Fitness RFQ """
fitness_rfq_form = FitnessForm()
if request.method == 'POST':
fitness_rfq_form = FitnessForm(request.POST)
if fitness_rfq_form.is_valid():
obj = fitness_rfq_form.save(commit=False)
obj.user = request.user
obj.save()
return HttpResponseRedirect(reverse('home'))
context = {'fitness_rfq_form': fitness_rfq_form}
return render(request, 'services/fitness_rfq.html', context)
But when i am trying to submit i am getting the validation error as below
Select a valid choice. [u'wl', u'ft'] is not one of the available choices.
Select a valid choice. [u'0', u'1'] is not one of the available choices.
So why it was showing above validation error even though we have mentioned it as MultiplechoiceField in ModelForm ?
You should not specify choices in the model field... this is the part that is failing validation.
Your form is working fine and the result of the multiple choice field is, of course, a list of selected choices. But then your model field is expecting a single value from the choices.
If you want to store the list of selected choices in a CharField you need to convert them to a string first, perhaps via json.dumps
Related
So this is the scenario. I allow my user to first input their vehicle brand with one form and then use another form to list down the models available for that vehicle brand. The information on the vehicles and the brands is stored in my database.
Refer to this image to get a better idea:
And this is my views.py:
def driver_dashboard_trip_brand (request, brand):
if request.method == "POST":
form = AddVehicleForm(request.POST)
else:
form = AddVehicleForm()
brands = VehicleBrand.objects.all()
context = {
"form":form,
"brands":brands,
"chosen_brand":brand
}
return render (request, "app/driver_dashboard.html", context)
And my forms.py:
class AddVehicleForm(forms.ModelForm):
model = forms.ModelChoiceField(queryset=VehicleModel.objects.all())
vehicle_colour = forms.ChoiceField(choices=COLOURS)
vehicle_number = forms.CharField(max_length=8, widget=forms.TextInput(attrs={'placeholder': 'eg: CAB-1234'}))
class Meta:
model = Vehicle
fields = ['model', 'vehicle_colour', 'vehicle_number']
So in order to set a query in the forms.py, I would first need to send the data from views.py to forms.py, and then I also need to do a query.
So my question is how can I query for all the car models from the VehicleModel database and create choices attribute for the form, once the user chooses the car brand.
My models.py...
class VehicleModel (models.Model):
brand = models.ForeignKey(VehicleBrand, on_delete=models.CASCADE)
model = models.CharField(max_length=30)
def __str__ (self):
return f"{self.brand} - {self.model}"
Its honestly not so hard, i kinda figured it out...
So this is my forms.py...
class AddVehicleForm(forms.ModelForm):
def __init__(self, brand=None, *args, **kwargs):
super(AddVehicleForm, self).__init__(*args, **kwargs)
self.fields['model'].queryset = VehicleModel.objects.filter(brand=brand)
model = forms.ModelChoiceField(queryset=VehicleModel.objects.all())
vehicle_colour = forms.ChoiceField(choices=COLOURS)
vehicle_number = forms.CharField(max_length=8, widget=forms.TextInput(attrs={'placeholder': 'eg: CAB-1234'}))
class Meta:
model = Vehicle
fields = ['model', 'vehicle_colour', 'vehicle_number']
class AddVehicleFormPost(forms.ModelForm):
model = forms.ModelChoiceField(queryset=VehicleModel.objects.all())
vehicle_colour = forms.ChoiceField(choices=COLOURS)
vehicle_number = forms.CharField(max_length=8, widget=forms.TextInput(attrs={'placeholder': 'eg: CAB-1234'}))
class Meta:
model = Vehicle
fields = ['model', 'vehicle_colour', 'vehicle_number']
Where the form AddVehicleForm allowed me to send the parameter as shown by typing form = AddVehicleForm(VehicleBrand.objects.filter(brand=brand).first()) in my views.py, but then when I wanted to save my form I needed to create another form in the forms.py without taking any query which is shown in AddVehicleFormPost.
Then i casually did,
if request.method == "POST":
form = AddVehicleFormPost(request.POST)
if form.is_valid():
In my views.py...
Here you have a nice tutorial on how to create dependent fields, you need to understand what's going on on the Server, and what's going on on the Client
I have a multiple choice field with a foreign key. I want to save which keeper was attending a training session and I want to list all keepers as a multiple choice field.
class AddAttendance(forms.ModelForm):
attendanceKeeper = Attendance.objects.only("keeper","present").all()
keeperValues = Attendance.objects.values_list("keeper__id", flat=True).distinct()
keeper = forms.ModelMultipleChoiceField(widget=forms.widgets.CheckboxSelectMultiple, queryset=Keeper.objects.filter(id__in=keeperValues, status=1))
class Meta:
model = Attendance
fields = ('keeper',)
def __init__(self, *args, **kwargs):
super(AddAttendance, self).__init__(*args, **kwargs)
self.initial["keeper"] = Keeper.objects.all()
However my problem is, I am not familiar how to handle a queryset in the view and how to loop through it and to save every instance with the value True or False.
I always get the value error that a queryset cannot be assigned
"Attendance.keeper" must be a "Keeper" instance
Can you help me how I access the queryset values and save them
def new_attendance(request, team_pk, package_pk):
if request.method == "POST":
form = AddAttendance(request.POST)
if form.is_valid():
for item in form:
attendance = item.save(commit=False)
attendance.keeper = get_object_or_404(AddAttendance.keeper)
attendance.team = get_object_or_404(Team, pk=team_pk)
attendance.created_date = timezone.now()
attendance.save()
return redirect(reverse('select_package', args=[package_pk, team_pk]))
else:
form = AddAttendance()
return render(request, 'attendance/new_attendance.html', {'form': form})
In the end I want to match keeper from the queryset and save True/False into the field present in my model
class Attendance(models.Model):
session = models.ForeignKey(Session)
keeper = models.ForeignKey(Keeper)
team = models.ForeignKey(Team)
present = models.BooleanField()
created_date = models.DateTimeField(default=timezone.now)
edited_date = models.DateTimeField(default=timezone.now)
You don't want a multiple choice field; you want a single choice. Only one keeper can be associated with each Attendance object.
You are doing a bunch of strange and unnecessary things here. You should remove most of this code, and use the ModelChoiceField which is the default for a ForeignKey. You don't want a checkbox widget either, since again that is for multiple choices; perhaps a radiobutton would be suitable.
class AddAttendance(forms.ModelForm):
class Meta:
model = Attendance
fields = ('keeper',)
widgets = {'keeper': forms.RadioSelect}
# remove the __init__ and the field definitions, you don't need them
...
form = AddAttendance(request.POST)
if form.is_valid():
attendance = item.save(commit=False)
attendance.team = get_object_or_404(Team, pk=team_pk)
attendance.created_date = timezone.now()
attendance.save()
return redirect(reverse('select_package', args=[package_pk, team_pk]))
There's no need to set the keeper explicitly in the view, since that's what the form is doing.
Can someone say, how create such form as in the picture below in Django?
I have model Product with field is_visable. In form I want to show all products with field is_visable. User can select checkboxes and change the value of is_visable field. In other words make products visable or invisable. I am thing about MultipleChoiceField in my form but not sure is it correct in my case.
models.py:
class Product(models.Model):
symbol = models.CharField(_('Symbol'), max_length=250)
name = models.CharField(_('Name'), max_length=250)
is_visible = models.BooleanField(default=False)
forms.py:
class ProductForm(forms.ModelForm):
product = forms.ModelChoiceField(widget=forms.CheckboxSelectMultiple, queryset=Product.objects.all())
views.py:
if request.method == 'POST':
form = ProductForm(data=request.POST)
if form.is_valid():
ids = form.cleaned_data.get('product') # Example: ['pk', 'pk']
for id in ids:
product = Product.objects.get(pk=id)
product.is_visible = True
product.save()
I think what you want to use is a ModelChoiceField in your form with a widget of CheckboxSelectMultiple.
A queryset for the ModelChoiceField is a required argument, so you can build the queryset like this:
visible_products = Product.objects.filter(is_visible=True)
product_field = forms.ModelChoiceField(queryset=visible_products,
widget=CheckboxSelectMultiple()
See this post for more details:
Django ChoiceField populated from database values
I am busy trying to get the id only in integer format preferably for the ModelChoiceField. I get the list to display but get's returned in a string format. Please helping me in retrieving the id of ModelChoiceField. I think I need to do this in the view.
forms.py
class ProjectForm(forms.ModelForm):
items = forms.ModelChoiceField(queryset=Project.objects.all())
class Meta:
model = Project
fields = ['items']
models.py
class Project(models.Model):
items = models.IntegerField(default=0, blank=True, null=True)
views.py
def ProjectView(request):
form = ProjectForm(request.POST)
if request.method == 'POST':
if form.is_valid():
save_it = form.save(commit=False)
save_it.save()
return HttpResponseRedirect('/')
else:
form = ProjectForm()
return render(request, 't.html', {'form': form })
From what I can tell, items should never be an IntegerField. Your usage has it set up to be a ForeignKey to a Project so you should just make that explicit
items = models.ForeignKey('self', null=True, blank=True)
Possibly with a better descriptive name than items.
Then, you don't need to define anything on the form, it just becomes a standard model form, with a standard model form usage.
I'm still learning Django. I have a wizard like form workflow where each form is filling out information in succession.
I have a model form that represents what I want inputted from the form:
Models.py
class AccountParameters(models.Model):
acctFilterName = models.ForeignKey(AccountFilters)
excludeClassification = models.ManyToManyField(ClassificationNames)
tradingCash = models.FloatField()
Forms.py
This is a dumbed down form and doesn't represent the real implementation. It was for testing.
class AccountSelectionForm(forms.ModelForm):
acctFilterName = forms.ModelChoiceField(queryset=AccountFilters.objects.all().values_list('acctFilterName', flat=True),
label="Account Filters:",
empty_label="Select Here..."
)
excludeClassification = forms.ModelMultipleChoiceField(queryset=ClassificationNames.objects.all().values_list('classificationName', flat=True),
label="Classifications Exclusion:"
)
tradingCash = forms.IntegerField(label="Remove accounts whose trading cash < % of AUM")
class Meta:
model = AccountParameters
fields =['excludeClassification', 'tradingCash',]
exclude = ['acctFilterName']
labels = {
'acctFilterName': _('Account Filters:')
}
views.py
def accountSelections(request): # NewRebalnce 2: AccountParameters with Accounts and Trading Form
if request.method == "POST":
form = AccountSelectionForm(request.POST)
if form.is_valid():
accountParameters = AccountParameters
#tradingCash = form.cleaned_data['tradingCash']
return render(request, 'NewRebalance_3.html', {'model_selection_form': ModelSelectionForm()})
else:
form = AccountSelectionForm()
return render(request, 'NewRebalance2.html', {'account_selections_form': form})
I'm not sure that I'm using Modelforms correctly. What I needed was a way to create a select drop down for my acctFilterName so I created the query set manually.
When I save the form it's not valid and in the form cleaned data I get the following:
Notice that the cleaned data only has the tradingCash field.
What am I doing wrong? Is there a better way to do this? Why is the Form in valid?
try to remove .values_list('acctFilterName', flat=True) from the ModelChoiceField and remove .values_list('classificationName', flat=True) from the ModelMultipleChoiceField.
They should be like this:
acctFilterName = forms.ModelChoiceField(
queryset=AccountFilters.objects.all(),
label="Account Filters:",
empty_label="Select Here...")
excludeClassification = forms.ModelMultipleChoiceField(
queryset=ClassificationNames.objects.all(),
label="Classifications Exclusion:")
.values_list will strip your queryset of all the data the ModelChoiceField needs to recognize the item, leaving only the model fields you specify as an argument. Namely, what you're removing here is the primary key of the model which is fundamental.
Why are you redeclaring the fields on your AccountSelectionForm ModelForm???
Better this way:
class AccountSelectionForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.fields['excludeClassification'].queryset = ClassificationNames.objects.all().values_list('classificationName', flat=True)
self.fields['acctFilterName'].queryset = AccountFilters.objects.all().values_list('acctFilterName', flat=True)
class Meta:
model = AccountParameters
fields =['excludeClassification', 'tradingCash',]
exclude = ['acctFilterName']
labels = {
'acctFilterName': _('Account Filters:')
}