I have two models, Route and Waypoint, and need to preserve the sequence of the waypoints allocated to the route. Route A to B and Route B to A have the same waypoints on the Route (mostly) , but the sequence is reversed.
class Flight_Route(models.Model):
name = models.CharField(max_length=50)
departure = models.ForeignKey(Airport,related_name = 'dep_airport',on_delete=models.CASCADE)
arrival = models.ForeignKey(Airport,related_name = 'arr_airport',on_delete=models.CASCADE)
exp_flight_time = models.DurationField(null=True,blank=True,default=timedelta(minutes=0))
alt_arr_airport = models.ForeignKey(Airport,related_name = 'alt_arr_airport',on_delete=models.CASCADE)
def __str__(self):
return str(self.name + ' alt : ' + str(self.alt_arr_airport.iata_code))
class Meta:
verbose_name = 'Flight Route'
verbose_name_plural = 'Flight Routes'
ordering = ['name','departure','arrival','exp_flight_time','alt_arr_airport',]
class Waypoint(models.Model):
name = models.CharField(max_length=50)
description = models.CharField(max_length=100,null=True,blank=True)
latitude = models.CharField(max_length=12,null=True,blank=True)
longitude = models.CharField(max_length=12,null=True,blank=True)
type = models.CharField(max_length=20,default='Fly-by or Flyover')
route = models.ManyToManyField(Flight_Route, blank=True, related_name="Waypoint_on_Route")
def __str__(self):
return str(self.name + ' ' + self.description)
class Meta:
verbose_name = 'Waypoint'
I use a model formset_factory on Waypoint in the HTML in order to capture the Waypoints and to add or delete them from the Route. I do not have an additional model to preserve the sequence, as the waypoint_route model generated by Django, has the sequence I need.
class FlightRouteUpdateView(UpdateView,LoginRequiredMixin):
form_class = FlightRouteForm
model = Flight_Route
template_name = 'flight/flight_route_update.html' #<app>/<model>_<viewtype>.html
def get_named_formsets(self, **kwargs):
RouteWaypointFormSet = modelformset_factory(Waypoint,form=WaypointForm,fields=('route','name','description','latitude','longitude','type',),exclude=None, extra=0, can_delete=True, can_delete_extra=True)
if self.request.method == "GET":
route = self.object
wps = route.Waypoint_on_Route.through.objects.all()
return {
'waypoints': RouteWaypointFormSet(prefix='waypoints', queryset = wps),
}
else:
return {
'waypoints': RouteWaypointFormSet(self.request.POST or None, self.request.FILES or None, prefix='waypoints'),
}
When I retrieve the related fields through the Waypoint model, the sequence is the Waypoint_id sequence (i.e. when the waypoint was created). This works fine with the formset, but doesn’t give the correct sequence.
My problem which I cannot seem to overcome, is that when I execute the query -through- the waypoint_route model, the sequence is as I want it, but the name of the queryset elements is not recognised by the formset.
I’m sure I’m missing something simple (like a change in the formset declaration or a change to the ManytoMany query) but I cannot seem to overcome this.
prior to the sorted sequence, my extract looked like this :
wps = route.Waypoint_on_Route.all()
with a resulting queryset of :
<QuerySet [<Waypoint: TAVLA South Africa : Limpopo>, <Waypoint: VLS Zambia : Lusaka>, <Waypoint: TIKAN Tanzania : Tikan>, <Waypoint: APNAD Uganda : Lake Victoria>,... ]>
the correct sequence for the waypoint sequence I retrieve by :
wps = route.Waypoint_on_Route.through.objects.all()
which results in the following queryset of :
<QuerySet [<Waypoint_route: Waypoint_route object (107)>, <Waypoint_route: Waypoint_route object (108)>, <Waypoint_route: Waypoint_route object (109)>, <Waypoint_route: Waypoint_route object (110)>,...]>
wps = route.Waypoint_on_Route.through.objects.all().prefetch_related('waypoint')
yields exactly the same result as above.
I have tried a number of variations to the query extract : e.g. looping through the queryset and extracting the waypoint instances – but this creates a list, and not a queryset which I can feed into the formset.
I have also tried to extract a value_set(‘waypoint’), but this is then not recognised by the formset as a queryset.
I currently am seeing the right number of records in the formset display if I use the Waypoint_route object, but the formset data is corrupted and no longer works. (I have tried to extract the Waypoint instances – and can display them in the html, but all the form controls are lost).
{% with named_formsets.waypoints as formset %}
<!-- inline form for waypoints start -->
{{ formset.management_form }}
<script type="text/html" id="waypoints-template">
<tr id="waypoints-__prefix__" class= hide_all>
{% for fields in formset.empty_form.hidden_fields %}
{{ fields }}
{% endfor %}
{% for fields in formset.empty_form.visible_fields %}
<td>{{fields}}</td>
{% endfor %}
</tr>
</script>
<div class="table-responsive" >
<table class="table">
<thead class="" style="font-weight: lighter ; color:lightblue">
<tr>
<th><span style="color: red;" col=2 class="required"> Waypoint*</span> </th>
<th><span style="color: steelblue;" col=4 class="required"> Description *</span> </th>
<th><span style="color: yellowgreen;" col=2 class="required">Latitude *</span> </th>
<th><span style="color: forestgreen;" col=2 class="required">Longitude *</span> </th>
<th><span style="color: salmon;" col=1 class="required">Type *</span> </th>
<th><span style="color: darkred;">Delete? </span></th>
<th></th>
</tr>
</thead>
<tbody id="item-waypoints"> <!-- id="item-inlineformsetname" -->
<!-- formset non forms errors -->
{% for error in formset.non_form_errors %}
<tr><td><span style="color: red">{{ error }}</span></td></tr>
{% endfor %}
{% for formss in formset %}
{{ formss.management_form }}
<tr id="waypoints-{{ forloop.counter0 }}" class= hide_all> <!-- id="inlineformsetname-counter" -->
{{ formss.id }}
{% for field in formss.visible_fields %}
<td>
{{field}}
{% for error in field.errors %}
<span style="color: red">{{ error }}</span>
{% endfor %}
</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
<small><a href="#" id="add-image-button" class="btn btn-outline-success add-waypoints">Create New Waypoint</a> </small><!-- id="add-inlineformsetname-button" -->
</div>
{% endwith %}
I have been though all the Django documentation, tried append, and subsets – but stopped at using sql query (as I’m sure there is a better way of resolving this).