dropdown is populated with the value changed to the field instead of pk when source is viewed.
However the form returns an object for this field and I still have to use Condition.condition_id to get desired result.Obviously I can make it work with an extra couple of lines of code but there should be a more direct way. If not then why have to_field_name at all?
Perhaps youâre using the wrong type of field here?
The purpose of a ModelChoiceField is to aid with the selection of an object. It wouldnât be doing what itâs supposed to do if it returned anything else.
Guess Iâm just thinking about it more as a form helper to build a dropdown list populated by the queryset.
I have a table with records that just has a condition name and condition id. I was using a ModelChoiceField to populate a dropdown for a user to select the condition. I only need the condition id of the selection to pass on to the next step of business logic. I thought it would work like a normal dropdown once rendered and the value of the option would be assigned to that field name.
I guess it wasnât designed for that. Still curious though why there would be an argument to change the values of the options(to_field_name) if you donât have access to those values anyway. I suppose it could be useful if you needed to access it via Javascript. .
Once you have the object, you have access to all the fields of that object.
The to_field_name does change the value on which it will do the search for the matching object, but by definition, a ModelSelectField is going to yield an object.
Iâm not understanding what youâre objecting to here.
Maybe if you post a small snippet of code showing what youâre trying to do in context, we might be able to clear this up.
Iâm not trying to object to anything just trying to learn and comprehend. I accept your answer it doesnât behave as a normal select. I was just asking in case I had missed something because it would save me some complexity in my code. Thanks for your time.
I think you have, which is why Iâm asking for a snippet of code.
You made the comment earlier:
which, on the surface, in an inaccurate statement. Itâs not âan extra couple lines of codeâ - itâs typically a few extra characters on one line of code.
This leads me to believe that youâre thinking itâs more work than what it generally is. Thatâs really what Iâm trying to clear up here.
def brand_search(request):
if request.method == 'POST':
form = BrandSearchForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
payload = {'category': cd['category'], 'brand': cd['brand']}
url = "https://ogboomer.pythonanywhere.com/someproject/someapp/"
for key in cd:
if key == 'condition':
payload[key] = cd[key].condition_id
else:
payload[key] = cd[key]
response = requests.post(url, json=payload)
data = response.json()
return JsonResponse(response.json(), safe=False)
The form will end up having several ModalChoiceFields. The way I see it, I will have to cycle through each field and convert each one that is an object to the desired string value. Then it can be json encoded to send to the my API on another server. If it was just the fieldname value combination I could skip the iteration and just send So yeah it does take some extra lines of code to âmake it workâ
First, what I would seriously suggest is that you change this from a ModelChoiceField to a ChoiceField. You can still use the query to retrieve the choices, but itâs not going to convert the response to an object reference.
But, getting outside the âcommon caseâ, you have a couple ways of making it work as-is.
If this is something consistent across all such instances of the data being submitted, thereâs nothing saying that you need to use the âcleaned_dataâ version. You could use the raw data from the data attribute of the form directly. Since youâre creating JSON from this form data, thereâs not a lot of value in converting the submitted data to an internal format only to convert it back again.
In other words, instead of creating another dict âpayloadâ, you could send form.data as the payload.
Or, you could check to see if the entity being assigned to payload is an object and retrieve the primary key from it:
payload = {
key: value.pk if 'models' in str(type(value)) else value
for key, value in cd.items()
}
Or, if you donât like the âtypeâ expression in that generator, you could create a list for that comparison.
For example, if you have a list of fields using the model select field named âselect_listâ:
payload = {
key: value.pk if key in select_list else value
for key, value in cd.items()
}
I originally was going with a ChoiceField but it actually doesnât take a queryset as an argument you have to supply an iterable of 2-tuples or a callable that will give you such.
This is the slap in the face I was looking for. New code that works.
def brand_search(request):
if request.method == 'POST':
form = BrandSearchForm(request.POST)
if form.is_valid():
data = form.data
# del data['csrfmiddlewaretoken']
url = "https://ogboomer.pythonanywhere.com/someproject/someapp/"
response = requests.post(url, json=data)
do_save_search(json.loads(response.content.decode('utf-8')))
return render(request, 'brandprofile/profile_detail.html', {'profile': data['profile_id'], 'form': form})
I had to comment out the del statement and deal with it on the API side as it was throwing an error that data was a query dictionary and unmutable.
I was thinking of cleaned_data in the terms of being safe data from things like code injection and what not.
A query, using the values_list function, returns a list of tuples.
e.g. User.objects.values_list('id', 'username')
First, the is_valid test checks for valid values. Even though youâre not going to use them, the clean process is going to ensure that the data provided does pass all the tests.
Beyond that, you arenât doing anything with the data - youâre just passing it along. Now, itâs nice to ensure that the data is clean, but ultimately, thatâs the responsibility of the service handling the request.
I donât know the model youâre trying to use here. But itâs basically going to be: condition = ChoiceField(choices=MyModel.objects.values_list('id', 'some_other_field'))
This works when MyModel is expected to be constant throughout the life of the process. (Itâs going to be evaluated at import time.)
If you need it to be more dynamic, then you can put that query in a function, and pass that function as the callable.
This works for me as the Condition table will not change. I think this would be the better route as it is less âoverheadâ than the ModelChoiceField.
Thanks for explaining it, Iâve learned quite a bit from this conversation.