Hanny
Hanny

Reputation: 682

ModelForm in Django - select is not populating with appropriate data?

I've got a model form in Django that displays nicely - but it's not pulling the appropriate information.

The select dropdowns appear, but are not populated with the options and I am struggling to figure out why.

My models look like this:

class Mileage(models.Model):
    start_location = models.ForeignKey(Location, on_delete=models.PROTECT, related_name='start_locations')
    end_location = models.ForeignKey(Location, on_delete=models.PROTECT, related_name='end_locations')
    miles = models.DecimalField(max_digits=8, decimal_places=2)
    user_id = models.IntegerField(null=True)

    def __str__(self):
        return self.miles

class Location(models.Model):
    name = models.CharField(max_length=255)
    address = models.CharField(max_length=255, null=True)
    latitude = models.DecimalField(max_digits=9, decimal_places=6, null=True)
    longitude = models.DecimalField(max_digits=9, decimal_places=6, null=True)
    user_id = models.IntegerField(null=True)

    def __str__(self):
        return self.id

class Trip(models.Model):
    start_location = models.CharField(max_length=255)
    end_location = models.CharField(max_length=255)
    miles = models.DecimalField(max_digits=7, decimal_places=2)
    user = models.ForeignKey(User, on_delete=models.PROTECT)
    trip_date = models.DateTimeField('trip date')

    def __str__(self):
        return self.id

My ModelForm looks like this:

class TripsForm(ModelForm):
    class Meta:
        model = Trip
        fields = ['start_location', 'end_location', 'miles', 'trip_date']
        widgets = {
            'start_location': forms.Select(
                attrs={
                    'class': 'form-control',
                    'id': 'start_location'
                }
            ),
            'end_location': forms.Select(
                attrs={
                    'class': 'form-control',
                    'id': 'end_location'
                }
            ),
            'miles': forms.NumberInput(
                attrs={
                    'class': 'form-control',
                    'id': 'miles',
                    'readonly': 'readonly'
                }
            ),
            'trip_date': forms.TextInput(
                attrs={
                    'class': 'form-control monthpicker datepicker',
                    'id': 'trip_date'
                }
            ),
        }

In my view I'm calling it like this from view.py:

# Create trip
def trip_create(request):
    # if this is a POST request we need to process the form data
    if request.method == 'POST':
        form = TripsForm(request.POST)
        # check whether it's valid:
        if form.is_valid():
            # Save the form -- will handle this all later
            trip.save()
            return HttpResponseRedirect('/thanks/')
    # if a GET (or any other method) we'll create a blank form
    else:
        form = TripsForm()
        # Return to trips with list of date
    return render(request, 'trips/create.html', {'form': form})

The 'start_locations' and 'end_locations' selects should be populated with all of locations - currently the selects are totally empty.

I've been looking through documentation: would a modelformset_factory() be something to dig into more in this case?

I'm just not sure how to proceed to get it to populate those dropdowns.

Upvotes: 1

Views: 518

Answers (1)

Alasdair
Alasdair

Reputation: 308779

Currently you are using a CharField for Trip.start_location and Trip.end_location. If you use a select widget, it's up to you to create the choices to populate it.

If you use a ForeignKey for your start_location and end_location fields, then Django will populate the choices for you.

class Trip(models.Model):
    start_location = models.ForeignKey(Location, on_delete=models.PROTECT, related_name='trip_start_locations')
    end_location = models.ForeignKey(Location, on_delete=models.PROTECT, related_name='trip_end_locations')

After making the change in your models, you'll have to make a migration, then migrate.

Note that I've included trip in the related_name, since the related name is used to take you from the Location model back to Trip. You might want to update the related_name for your Mileage model to include mileage.

Upvotes: 1

Related Questions