def operator_vehicles(request, slug=None, parent=None): operators = Operator.objects.select_related('region') if slug: try: operator = get_object_or_404(operators, slug=slug.lower()) except Http404: operator = get_object_or_404(operators, operatorcode__code=slug, operatorcode__source__name='slug') vehicles = operator.vehicle_set.filter(withdrawn=False) elif parent: operators = list(operators.filter(parent=parent)) vehicles = Vehicle.objects.filter( operator__in=operators, withdrawn=False).select_related('operator') if not operators: raise Http404 operator = operators[0] vehicles = vehicles.order_by('fleet_number', 'fleet_code', 'reg', 'code') if not parent: latest_journeys = Subquery( VehicleJourney.objects.filter( vehicle=OuterRef('pk')).order_by('-datetime').values('pk')[:1]) latest_journeys = vehicles.filter(latest_location=None).annotate( latest_journey=latest_journeys) latest_journeys = VehicleJourney.objects.filter( id__in=latest_journeys.values('latest_journey')) prefetch = Prefetch('vehiclejourney_set', queryset=latest_journeys.select_related('service'), to_attr='latest_journeys') vehicles = vehicles.prefetch_related(prefetch, 'features') pending_edits = VehicleEdit.objects.filter( approved=None, vehicle=OuterRef('id')).only('id') vehicles = vehicles.annotate(pending_edits=Exists(pending_edits)) vehicles = vehicles.select_related('latest_location__journey__service') vehicles = vehicles.select_related('livery', 'vehicle_type') submitted = False revisions = False breadcrumb = [operator.region, operator] form = request.path.endswith('/edit') if form: if not request.user.is_authenticated: return redirect(f'/accounts/login/?next={request.path}') breadcrumb.append(Vehicles(operator)) initial = { 'operator': operator, 'other_colour': '#ffffff', } if request.method == 'POST': form = EditVehiclesForm(request.POST, initial=initial, operator=operator) if not form.has_really_changed(): form.add_error(None, 'You haven\'t changed anything') elif form.is_valid(): data = { key: form.cleaned_data[key] for key in form.changed_data } vehicle_ids = request.POST.getlist('vehicle') now = timezone.now() revisions, changed_fields = do_revisions(vehicle_ids, data) if revisions: Vehicle.objects.bulk_update( (revision.vehicle for revision in revisions), changed_fields) for revision in revisions: revision.datetime = now if request.user.is_authenticated: revision.user = request.user VehicleRevision.objects.bulk_create(revisions) revisions = len(revisions) if data: # this will fetch the vehicles list # - slightly important that it occurs before any change of operator ticked_vehicles = [ v for v in vehicles if str(v.id) in vehicle_ids ] edits = [ get_vehicle_edit(vehicle, data, now, request) for vehicle in ticked_vehicles ] edits = VehicleEdit.objects.bulk_create(edit for edit in edits if edit) submitted = len(edits) if 'features' in data: for edit in edits: edit.features.set(data['features']) form = EditVehiclesForm(initial=initial, operator=operator) else: form = EditVehiclesForm(initial=initial, operator=operator) if operator.name == 'National Express': vehicles = sorted(vehicles, key=lambda v: v.notes) if not vehicles: raise Http404 paginator = Paginator(vehicles, 1000) page = request.GET.get('page') vehicles = paginator.get_page(page) features_column = not parent and any(vehicle.features.all() for vehicle in vehicles) columns = set(key for vehicle in vehicles if vehicle.data for key in vehicle.data) for vehicle in vehicles: vehicle.column_values = [ vehicle.data and vehicle.data_get(key) or '' for key in columns ] response = render( request, 'operator_vehicles.html', { 'breadcrumb': breadcrumb, 'parent': parent, 'operators': parent and operators, 'object': operator, 'today': timezone.localtime().date(), 'vehicles': vehicles, 'paginator': paginator, 'code_column': any(v.fleet_number_mismatch() for v in vehicles), 'branding_column': any(vehicle.branding for vehicle in vehicles), 'name_column': any(vehicle.name for vehicle in vehicles), 'notes_column': any(vehicle.notes and vehicle.notes != 'Spare ticket machine' for vehicle in vehicles), 'features_column': features_column, 'columns': columns, 'edits': submitted, 'revisions': revisions, 'revision': revisions and revision, 'form': form, }) return response
def operator_vehicles(request, slug): operators = Operator.objects.select_related('region') try: operator = get_object_or_404(operators, slug=slug) except Http404: operator = get_object_or_404(operators, operatorcode__code=slug, operatorcode__source__name='slug') vehicles = operator.vehicle_set latest_journeys = Subquery(VehicleJourney.objects.filter( vehicle=OuterRef('pk') ).order_by('-datetime').values('pk')[:1]) latest_journeys = vehicles.filter(latest_location=None).annotate(latest_journey=latest_journeys) latest_journeys = VehicleJourney.objects.filter(id__in=latest_journeys.values('latest_journey')) prefetch = Prefetch('vehiclejourney_set', queryset=latest_journeys.select_related('service'), to_attr='latest_journeys') vehicles = vehicles.prefetch_related(prefetch) vehicles = vehicles.order_by('fleet_number', 'reg', 'code') vehicles = vehicles.select_related('vehicle_type', 'livery', 'latest_location__journey__service') edit = request.path.endswith('/edit') submitted = False if edit: form = EditVehiclesForm(request.POST, operator=operator, initial={ 'operator': operator }) if request.POST and form.is_valid(): ticked_vehicles = (vehicle for vehicle in vehicles if str(vehicle.id) in request.POST.getlist('vehicle')) data = {key: form.cleaned_data[key] for key in form.changed_data} submitted = len(VehicleEdit.objects.bulk_create( get_vehicle_edit(vehicle, data) for vehicle in ticked_vehicles )) if form.cleaned_data.get('operator') and form.cleaned_data['operator'] != operator: Vehicle.objects.filter(id__in=request.POST.getlist('vehicle')).update(operator=operator) else: form = None pending_edits = VehicleEdit.objects.filter(approved=False, vehicle=OuterRef('id')) vehicles = vehicles.annotate(pending_edits=Exists(pending_edits)) if not vehicles: raise Http404() if operator.name == 'National Express': for v in vehicles: parts = v.notes.split() if parts and parts[-1][-1].isdigit(): v.fleet_number = parts[-1] if v.fleet_number.isdigit(): v.fleet_number = int(v.fleet_number) v.notes = ' '.join(parts[:-1]) vehicles = sorted(vehicles, key=lambda v: v.fleet_number if type(v.fleet_number) is int else 0) vehicles = sorted(vehicles, key=lambda v: v.notes or 'z') return render(request, 'operator_vehicles.html', { 'breadcrumb': [operator.region, operator], 'object': operator, 'today': timezone.localtime().date(), 'vehicles': vehicles, 'code_column': any(v.fleet_number_mismatch() for v in vehicles), 'branding_column': any(vehicle.branding for vehicle in vehicles), 'name_column': any(vehicle.name for vehicle in vehicles), 'notes_column': any(vehicle.notes for vehicle in vehicles), 'edit_url': reverse('admin:vehicles_vehicle_changelist'), 'edit': edit, 'submitted': submitted, 'form': form, })