I've tried all possible solutions on several threads and I'm still unable to fix the problem. I have the following code:
models.py
class CustomerVisit(models.Model):
start_date = models.DateField()
end_date = models.DateField()
customer = models.ForeignKey(Customer)
address = models.ForeignKey(Address)
forms.py
address = forms.ModelChoiceField(label='Address',
queryset=Address.objects.none(),
widget=forms.Select(attrs={'style': 'width: 100%;'}))
customer = forms.ModelChoiceField(label='Customer',
queryset=Customer.objects.all(),
widget=forms.Select(attrs={'style': 'width: 100%;'}))
views.py
if request.method == "POST":
# Cleaning fields
post = request.POST.copy()
post['address'] = Address.objects.get(id=post['address'])
post['start_date'] = dateparser.parse(post['start_date'])
post['end_date'] = dateparser.parse(post['end_date'])
# Updating request.POST
request.POST = post
form = CustomerVisitForm(request.POST)
if form.is_valid():
form.save(commit=True)
return redirect("customervisit:calendar")
js
$("#id_customer").select2({}).on("change", function () {
var customer_id = $("#id_customer").val();
var id_address = $("#id_address");
id_address.select2({
ajax: {
url: '/get_customer_address/' + customer_id,
dataType: "json",
type: "GET",
data: function (params) {
var queryParameters = {
term: params.term
}
return queryParameters;
},
processResults: function (data) {
return {
results: $.map(data, function (item) {
return {
text: item.text,
id: item.id
}
})
};
}
}
});
});
My address
select its being populated based on customer
selection using ajax call using select2. After reading several threads I noticed that modelchoicefield
expects a Address
object so that's why I'm using the following code on my view before the form is being validated: post['address'] = Address.objects.get(id=post['address'])
but I'm still getting the Select a valid choice. That choice is not one of the available choices.
error
I'm using queryset=Address.objects.none(),
because I need an empty select
Problem solved.
If someone in the future have the same error as me, checking to_python
method from the ModelChoiceField
saved my day:
def to_python(self, value):
if value in self.empty_values:
return None
try:
key = self.to_field_name or 'pk'
value = self.queryset.get(**{key: value})
except (ValueError, TypeError, self.queryset.model.DoesNotExist):
raise ValidationError(self.error_messages['invalid_choice'], code='invalid_choice')
return value
So I changed my queryset
to queryset=Address.objects
instead of queryset=Address.objects.none()
or queryset=Address.objects.all()
Thanks Daniel Roseman for your comments
I know what you're trying to achieve, my solution would be to initialise the field as charfield with widget select, and then override the clean method. Example:
class InvoiceForm(forms.ModelForm):
customer = forms.CharField(widget=forms.Select(attrs={'style': 'min-width: 150px;'}))
class Meta:
model = Invoice
exclude = ['id', 'created', 'is_paid']
def clean_customer(self):
customer_id = self.cleaned_data['customer']
customer = Customer.objects.get(id=customer_id)
if customer:
return customer
else:
raise ValidationError("Customer ID invalid")
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With