Returning Table Values from User Selection

Within models.py I built a class named Player populated with firstName, lastName and other related contact information elements. I have built a form where I can reference the Player object. I can’t quite figure out how get a charField to populate with the firstName of the Player when the lastName is selected from a Select field. I would like to do this prior to posting the form. This is similar to data binding in MS Access for instance. I’m sure this can be done but I’m not sure what’s lacking, my Python knowledge or my Django models/forms knowledge.
Like selecting a part number and having any other class elements displayed before positing the order.
Any help or hints would be appreciated. I’ve poured over the model docs and can’t find any examples that speak to what I’m trying to accomplish. It seems trivial. I suspect I would have to create a method for each object. Maybe using the object.get() method but how to do object.get(id_of_the_lastName_the _user_selected) if that makes sense.

Are you looking at the type of situation, where the browser is displaying a form, the user selects (or types in) the Last Name, and you want that form to be updated with the data found in the database - without a page refresh?

If so, this is done with JavaScript and an AJAX call. The JavaScript on the page calls the view on the server that can do the search and return the desired data to the browser. The JavaScript receives that response and updates the page.

Yes, the associated value is returned in the rendered form and before the form is posted. The user selects the lastName and I would like to be able to display any other class member (firstName, address, phoneNumber…) within the class, on the form. This allows the user to create a list (roster) of players using the lastName in a select field in each row.
So JavaScript and AJAX is the way that this is accomplished? That explains why there’s no information on how to do this with Django and Python. I was thinking that a queryset might be the way forward.
Do you have an example of this functionality? If not, where I could find an example?

Technically, it’s a combination of the two.

You need the JavaScript on the browser to detect when the focus has left the lastName field in the form.

That JavaScript can then send that lastName as a request (using AJAX) to a URL.

The URL is assigned to a Django view that you would need to write.

The view does the lookup by last name, and returns the data to the JavaScript (frequently, as a JSON dict)

The JavaScript then updates the DOM by inserting the values received from the server into the form.

Django can’t do this by itself because it has no visibility into what goes on in the browser. It’s running in the server, not on the client.

I’m not in a location today where I can easily find any samples - but keep in mind that you’re looking for two different things. Don’t try to do a single search to find both.

First, you need to find the JavaScript that you want to use to do the work in the browser as described above. How you do this typically depends upon what (if any) JavaScript frameworks you may already be using. (Implementations would differ depending upon whether you’re using plain JavaScript, jQuery, Vue, Angular, HTMX, etc.)

Completely independent of that is the Django view. You’ll be writing a standard view that takes the lastName as a parameter (your choice of url parameter, query variable, post request etc), does the lookup, and returns the result - probably as a JsonResponse.
(You’ll also need to decide how you’re going to handle the error conditions - no match found or multiple matches found.)

Now, you are likely to find more blog posts, tutorials, and examples for using the JavaScript to update the page itself and not a form. But that doesn’t matter. The technique will be the same, only the destination of the data within the DOM will change. You can still use the patterns those articles provide as a guide.

This is great information! You’ve given me some much needed hope. I might actually be able to solve this problem! I’ll start with Brad Traversy’s tutorial on AJAX to refresh my memory.
Thanks again Ken.

I was able to get it working after a lot of frustration. No code examples that I could find anywhere. Here’s the JavaScript I came up with

selectPlayer = document.getElementById('lastName');
selectPlayer.addEventListener('change', onChange);

function onChange(e){
  let lastNameSelected;

// Returns the text value of the selected Player. 
  lastNameSelected = e.target.options[e.target.selectedIndex].text;

// SEND
  const xhr = new XMLHttpRequest();
  // xhr.open('GET',`http://localhost:8000/getfirstName/<${lastNameSelected}>`, true);
  xhr.open('GET',`http://localhost:8000/getfirstName/${lastNameSelected}`,true);
  
  console.log('lastName Selected:', lastNameSelected);
    
  // RECEIVE 
  xhr.onload = function() {
    if(this.status == 200) {
      const response = this.responseText;
      console.log("from Django:", response);
      document.getElementById('firstName').innerHTML = `${this.response}`;
    }
  }
    
  xhr.send();
  e.preventDefault();
  }

Here’s the view

def getfirstName(request, lastNameSelected):
  name = Player.objects.get(lastName = lastNameSelected)
  firstName = name.firstName
  dob = name.DOB
  lastTeam = name.previousTeamName
  level = name.previousTeamCategory
  zone = name.areaAssociation

  # print(name)
  print('Last Name:', lastNameSelected)
  print('First Name:', firstName)
  print('Birthdate:', dob)
  print('Last Team:', lastTeam)
  print('Level:', level)
  print('Zone:', zone)

  return HttpResponse(firstName)

Here’s the urlpattern…

path('getfirstName/<lastNameSelected>', views.getfirstName, name='getfirstName'),

This works good for one returned value. But as you can see there are 5. I have not been able to find any code examples that send more than one value. Any idea why? Is this not done?
I don’t think I’m re-inventing the wheel. Surely I can create a dictionary or an array and package that up as an HttpReponse, no? Let’s say that I create a dictionary, should I do that with Json?
Also, what about the JavaScript unpacking on the “other side”? Do you have any hints on how to do that? I’m thinking that I should be able to create an object out of the response and unpack each element. Am I on the right track?

One of the problems with searching for information among blog posts, etc, is finding current information. (Also, evaluating the credibility of those sources is difficult if you don’t already have some knowledge of the topic.) Unfortunately, the method you’ve chosen for this is old, and not the easiest way to handle it.

Start with reading Fetch API - Web APIs | MDN and continue on with Using the Fetch API - Web APIs | MDN. Then if you want to search further, search for “JavaScript Fetch”.

Now, leaving that aside for the moment, your response can return anything you want to return.

You can render a template with a full queryset of data and return that. You are not in any way restricted as to the type or quantity of data returned, provided the JavaScript knows what to expect. If the JavaScript is expecting HTML to be returned, you can return any HTML. If the JavaScript is expecting JSON to update individual elements, you can return any amount of JSON - again, as long as the JavaScript knows what to do with it.

What is common when returning HTML is to replace an entire div. If you’re formatting the data on the server with a template, you can create a template for just the data to be returned.

Now, in your particular case for updating a form, you might want to do something different than this.

You could return a JsonResponse, where the JSON data being returned is a list of dicts, where each dict has a key for the html element to be updated and a key for the value to inject into that field. Your JavaScript then can iterate over that list and update those fields appropriately.

I read up on fetch and its use. I changed from Ajax to Fetch and it’s working as it was before. I’m able to send the request to Django, do a search and get back the values I need.

I need to return the individual elements from the Django search in one payload that can be extracted on JS side. Then those individual elements (firstName, DOB, Address, for example) will be placed into their assigned positions in the form via their tag id. This is all done when a user selects only the lastName on the form and without refreshing the page.

On the Python side the view receives the lastName from JS, a search is done and each element is stored in its own variable. One variable or all variable are returned via HttpResonse. I’m able to view one or all returned values in the JS console from the fetch.

What I can’t figure out yet is how compose a payload (list, array, dictionary) then extract the individual elements on the JS side. I have seen some examples of forEach, but have been unsuccessful so far. I think a loop is the way to extract the values but looping through what, an array, list or dictionary sent from Django. I don’t see a need to use JSON, unless you think it would be more appropriate. Http works but I need to sort the group of elements on the JS side.

fetch(`http://localhost:8000/getfirstName/${lastNameSelected}`)
    .then(function(res) { 
      return res.text(); // returns a promise, need another then.
    })
    .then(function(data) {
      console.log(data);
      console.log(Array.isArray(data)); // False
            
      document.getElementById('firstName').innerHTML = data;
      // document.getElementById('Address').innerHTML = data;
      // document.getElementById('Phone').innerHTML = data;
      // document.getElementById('Position').innerHTML = data;
    })
    .catch(function(err){
      console.log(err);
    });
}
def getfirstName(request, lastNameSelected):
  name = Player.objects.get(lastName = lastNameSelected)
  firstName = name.firstName
  dob = name.DOB
  lastTeam = name.previousTeamName
  level = name.previousTeamCategory
  zone = name.areaAssociation

  # print(name)
  print('Last Name:', lastNameSelected)
  print('First Name:', firstName)
  print('Birthdate:', dob)
  print('Last Team:', lastTeam)
  print('Level:', level)
  print('Zone:', zone)

  # response = [{'firstName': [firstName],
  # 'dob':[dob],
  # 'lastTeam':[lastTeam],
  # 'level':[level],
  # 'zone':[zone]}]
  
  response = (firstName, dob, lastTeam, level, zone)

  # return JsonResponse(response)
  return HttpResponse(response)
  # return HttpResponse({firstName,dob, lastTeam, level, zone})

console.log

Except, it’s using JSON that facilitates:

If I were solving this, my view would look something like this:

def getfirstName(request, lastNameSelected):
  name = Player.objects.get(lastName = lastNameSelected)

  # Note, the fields you show in your snippets don't align with each other.
  # You're referencing one set of fields in your view, but a different set
  # of fields in your group of getElementById functions. You would need
  # to adjust this to match the keys with the data elements.

  # Each key in this dict is the element ID of the html element to be updated.
  response = {
      'firstName': name.firstName,
      'Address':  name.address,
      'Phone': name.phone,
      'Position': name.position
  }

  return JsonResponse(response)

Then, in your JavaScript, you’ve received a JSON object.

(Note, I’m kinda winging this - this may require some fiddling to get working correctly, but hopefully it’s enough to get you going.)

Side Note: I’m not really familar with the Fetch API. We use jQuery in our systems and rely upon its AJAX functions.

Thanks Ken, it works now. Not sure why exactly. I changed the response to the list you created. I had done that before and didn’t get it to work. Also now using the JsonResponse you used. The dot convention is working on the JS side enabling me to retrieve each item.

My next challenge is create the same functionality in each row in the table. I’m using getElementById and passing in a tag. Which is fine for one tag but there are 24 players. So the user selects a players last name in each of 24 rows. I’ll have to think of a function for this.

document.getElementById(key).innerHTML = data[key];

That line of code above might do the trick. I’ll try to pass in a tag.
Have you ever written anything like what I’m describing?

The ID attribute on a page must be unique. You cannot have a situation where getElementById can return more than one element. This is an absolute don’t do this.

If you’re creating a set of common forms for a model, you’ll want to look at formsets. A formset takes care of the logic to assign unique IDs to each form.

What you will want to do is include something like the row number in the request so that the view can generate the right ID references for the response.

(Keep in mind that since you’re triggering this on a field, you’re going to be making a call to the view for each row. So you’re only going to retrieve one row’s worth of data for each call.)

I did not create a list, I created a dict. Or, perhaps to be more precise, I created a dict intended to be converted into a JSON object.

Notice some of the differences between what I’ve provided and what was in your previous attempt. Your earlier attempt as shown in the code was creating a list for each field. (You had the brackets around the variable names.)

Is it possible to insert the fetched values into the database? I mean, I’m sure it is, but how?
Without repeating what I’ve done already, now I have a form with values some of them came from the form.

<tr>
            <th scope="row">F1</th>
            <td>{{ form.f1_tryoutJersey }}</td>
            <td id="f1lastName">{{ form.f1 }}</td>
            <td id="f1firstName">{{ form.f1FirstName }}</td>
            <td id="f1DOB"></td>
            <td id="f1lastTeam"></td>
            <td id="f1level"></td>
            <td id="f1zone"></td>
          </tr>

JS section

f1 = document.getElementById('f1lastName');
f1.addEventListener('change', f1onChange);

function f1onChange(e) {
  let lastNameSelected;
  lastNameSelected = e.target.options[e.target.selectedIndex].text;
  fetch(`http://localhost:8000/getfirstName/${lastNameSelected}`)
  .then(function(res) { 
    return res.json(); // returns a promise, need another then.
  })
  .then(function(data) {
    firstName = data.firstName;
    DOB = data.dob
    lastTeam = data.lastTeam;
    level = data.level;
    zone = data.zone;
    
    // if (data.firstName === '-------') console.log('True')

    document.getElementById('f1firstName').innerHTML = firstName;
    document.getElementById('f1DOB').innerHTML = DOB;
    document.getElementById('f1lastTeam').innerHTML = lastTeam;
    document.getElementById('f1level').innerHTML = level;
    document.getElementById('f1zone').innerHTML = zone;
    console.log('F1:',lastNameSelected)
    
  })
  .catch(function(err){
    console.log(err);
  });
}

Most of them came back using fetch were inserted into the form using getElemebyById. So when I post the completed form, how do I push the fetched values into the database?

I don’t understand the requirements here.

If you’re returning the same values that you retrieved from the database, why would you want to put those same values back into the database? Those values are already there.

The values from the tryout roster are stored in a roster database.

When you say a “Roster database”, do you mean another table in the same database? Or are you actually getting this data from a different database?

Rosters are stored in a table in the same database. My plan was/is to create a form with 24 positions. Each position has a last name field from the table that contains our entire list of players. The user selects the last name, the JS code runs and populates the form with first name, dob, last team …
So after the form has been filled in and ready to be posted there are values that exist in the form but not connected to a field in the roster table. I’m not sure how to do this, or if this is possible.

The “database appropriate” method of doing this is to change your lastName field in your Player model to be a ForeignKey to the Roster model, perhaps with the name roster. Then, whenever your need to access that specific information, you access it directly from the Roster model.

Your form then would use a ModelChoiceField, allowing the user to select the individual for that row.

Note, if you’ve got more than about 50 entries, the select field is probably too awkward to use directly. In that case you would want to implement something like the JavaScript select2 with the Django module django-select2.

But the last thing you want to do under any circumstance is to replicate data throughout your database that doesn’t need to be duplicated. (That’s a principle of proper database design for relational databases, and is not Django-specific.)

I have it the other way around, a foreignKey to the Player model. The Player model is constructed from a registration list sent to me in an excel spreadsheet that I clean and upload to the database. It’s interesting that you suggest the other way around. I need to think about that. This project is complicated on a number of fronts. The database design is one of them. We will have over a hundred players trying out.
I understand what replicating data unnecessarily is to be avoided. I’m afraid I’m not skilled enough as a programmer at this point to know exactly how to avoid it in this case. The rosters need to be created for the staff and players and we need to keep track of who was at each tryout.
Can you confirm that there is no way to capture what came back from the fetch and store it in the tryout Roster table? I’m trying to visualize what that looks like practically in html/JavaScript using innerHTML like;

document.getElementById('f1zone').innerHTML = zone;

where zone is

function f1onChange(e) {
  let lastNameSelected;
  lastNameSelected = e.target.options[e.target.selectedIndex].text;
  fetch(`http://localhost:8000/getfirstName/${lastNameSelected}`)
  .then(function(res) { 
    return res.json(); // returns a promise, need another then.
  })
  .then(function(data) {
    firstName = data.firstName;
    DOB = data.dob
    lastTeam = data.lastTeam;
    level = data.level;
    zone = data.zone;

I’m hoping I asked that correctly, or at least in a way that makes sense. The values are coming back but with the innerHTML there just put in the target on the page using the tag. I need the to be placed into the Django template tag like

<td id="f1firstName">{{ form.zone }}</td>

Hope that makes sense.

Not the way you’re currently doing it, no - because you’re not populating form fields, you’re directly injecting text on to the page. You would need to define those fields as form fields and set the values of those fields with the data returned from the server.

I’m confused now.

What table contains the data you’re uploading from the spreadsheet?

What table is being edited by your form on the page?

If it’s the Player model containing the uploaded data and the Roster model being updated by the web page, then you have it correct. In that case, yes, the Roster model would have the ForeignKey to Player. So swap those table names in my previous response.

So if I define those fields as form fields and set the value of those fields with the data returned from the server, what I’m trying to achieve is possible is what I’m reading. Please confirm. I’ll press on in the current direction unless you tell me the way I’m doing is way off base.
What I’m trying to learn here is both;

  1. Is this possible and;
  2. Would a programmer with your similar experience do what I’m doing the way I’m doing it. As in is there a smarter or more elegant or more efficient way of retrieving and storing the values. Understandably there are probably many ways to do this, I’m really more interested in keeping it simple and maintainable.

The player Player model is where the spreadsheet get’s uploaded.

The Tryout Roster is being edited by the form.