Trilla
Trilla

Reputation: 771

MultiValueDictKeyError at /connect/

I'm trying to have all location functionality on one page, such as get users location, post it to the database, then filter results based on a user-inputted kilometre radius value.

I am getting MultiValueDictKeyError at /connect/ 'latitude' because the POST request is going to

location = Location(latitude=request.POST['latitude'], longitude=request.POST['longitude'], user = request.user)

when it should be going to

if request.POST['radius']:
            radius_km = request.POST.get('radius', 0)

I researched how to stop this happening and saw I could do if request.POST['radius']: to direct the post request to the right function.

This hasn't helped with the error unfortunately.

Am I missing something?

views.py

class ConnectView(View):
    template_name = 'connect/home.html'
    def get(self, request, *args, **kwargs):
        f = ProfileFilter(request.GET, queryset=Profile.objects.exclude(user=request.user))
        context = {
            'users': User.objects.exclude(username=request.user),
            'friends': Friend.objects.filter(current_user=request.user),
            'filter': f,
        }
        return render(request, self.template_name, context)

    def post(self, request, *args, **kwargs):
        location = Location(latitude=request.POST['latitude'], longitude=request.POST['longitude'], user = request.user)
        location.save()
        if request.POST['radius']:
            radius_km = request.POST.get('radius', 0)
            queryset = User.objects.annotate(
                radius_sqr=pow(models.F('loc__latitude') -
                request.user.loc.latitude, 2) + pow(models.F('loc__longitude') -
                request.user.loc.longitude, 2)
                ).filter(
                radius_sqr__lte=pow(int(radius_km) / 9, 2)
                ).exclude(username=request.user)
            context = {'users': queryset}
        return JsonResponse({'message': 'success'})

home.html

<script>
  var pos;

  var $demo;

  function getLocation() {
    if (navigator.geolocation) {
      navigator.geolocation.getCurrentPosition(showPosition);
    } else {
      $demo.text("Geolocation is not supported by this browser.");
    }
  }

  function showPosition(position) {
    pos = position;
    var { latitude, longitude } = pos.coords;
    $('#btn_submit').attr("disabled", null);
  }

  $(document).ready(function() {
    $demo = $("#demo");
    $('#btn_submit').on('click', function() {
      var data = pos.coords;
      data.csrfmiddlewaretoken = $('input[name=csrfmiddlewaretoken]').val();
      $.post('', data, function() {
        alert("Location Confirmed!");
      });
    });
  });

</script>

      <h1>Connect with people.</h1>

            <!-- GET window.location IP Address / lat lon coordinates -->
            <p id="demo"></p>
            <button onclick="getLocation()" class="btn btn-warning" id="confirm">1. Find Location</button>
            <button type="submit" id="btn_submit" name="btn_submit"  class="btn btn-success" disabled>2. Submit Location </button>

            <!-- filter by profile attributes -->
            <form method="GET">
                {{ filter.form }}
                <button type="submit" class="small">Search.</button>
            </form>

            <!-- enter radius to filter by location-->
            <form method="POST">
              {% csrf_token %}
              <input type="number" name="radius">
              <input type="submit" value="filter by kilometers">
            </form>

Upvotes: 0

Views: 150

Answers (2)

dirkgroten
dirkgroten

Reputation: 20702

request.POST is just a python dictionary (almost, it can have multiple values for the same key, hence the class name MultiValueDict). So just treat it as a normal dictionary object:

  • dict[key] raises a KeyError if the key doesn't exist
  • dict.get(key) returns the value for key or None if it doesn't exist.
  • dict.get(key, default) returns the value for key of default if the key doesn't exist.

request.POST['latitude'], request.POST['longitude'] and request.POST['radius'] will throw this exception if these keys aren't in the POST parameters. Always use request.POST.get(param_name) when checking what is being submitted.

In your case, you should also add an if 'latitude' in request.POST and 'longitude' in request.POST clause before doing anything with latitude and longitude.

Upvotes: 1

TechSavy
TechSavy

Reputation: 1340

In your post method, you have added request.POST['latitude'], which you might not be passing with the post method. And your if.. condition comes after that. Therefore Django gives you error, because it doesn't find any parameter with this name, and will stop the further execution.

So, on post request if you are not passing latitude longitude parameters try writting it as:

request.POST.get('latitude', None)

or,

put your if.. condition before accessing latitude and longitutde parameters.

Upvotes: 2

Related Questions