Compare commits
No commits in common. "070849c427ad1f41ad7bd0ad32e8ca1b5119b596" and "6884084f2a250dd530e5dda24fe0d6f25a5726a3" have entirely different histories.
070849c427
...
6884084f2a
@ -18,7 +18,7 @@ function App() {
|
||||
element: <Home />,
|
||||
},
|
||||
{
|
||||
path: "/station/:theme/:stationSlug",
|
||||
path: "/station/:theme/:stopId",
|
||||
element: <Station />
|
||||
}
|
||||
])
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {Autocomplete, TextField} from "@mui/material";
|
||||
import {useRef, useState} from "react";
|
||||
|
||||
function AutocompleteStation(params) {
|
||||
function AutocompleteStop(params) {
|
||||
const [options, setOptions] = useState([])
|
||||
const previousController = useRef()
|
||||
|
||||
@ -17,7 +17,7 @@ function AutocompleteStation(params) {
|
||||
const controller = new AbortController()
|
||||
const signal = controller.signal
|
||||
previousController.current = controller
|
||||
fetch("/api/core/station/?search=" + value, {signal})
|
||||
fetch("/api/gtfs/stop/?location_type=1&search=" + value, {signal})
|
||||
.then(response => response.json())
|
||||
.then(data => data.results)
|
||||
.then(setOptions)
|
||||
@ -40,7 +40,24 @@ function AutocompleteStation(params) {
|
||||
}
|
||||
|
||||
function getOptionGroup(option) {
|
||||
return option.country
|
||||
switch (option.gtfs_feed) {
|
||||
case "FR-SNCF-TGV":
|
||||
case "FR-SNCF-IC":
|
||||
case "FR-SNCF-TER":
|
||||
return "TGV/TER/Intercités"
|
||||
case "FR-IDF-TN":
|
||||
return "Transilien"
|
||||
case "FR-EUROSTAR":
|
||||
return "Eurostar"
|
||||
case "IT-FRA-TI":
|
||||
return "Trenitalia France"
|
||||
case "ES-RENFE":
|
||||
return "RENFE"
|
||||
case "AT-OBB":
|
||||
return "ÖBB"
|
||||
default:
|
||||
return option.gtfs_feed
|
||||
}
|
||||
}
|
||||
|
||||
export default AutocompleteStation;
|
||||
export default AutocompleteStop;
|
@ -1,11 +1,11 @@
|
||||
import AutocompleteStation from "./AutocompleteStation"
|
||||
import AutocompleteStop from "./AutocompleteStop"
|
||||
import {useNavigate} from "react-router-dom"
|
||||
|
||||
function Home() {
|
||||
const navigate = useNavigate()
|
||||
|
||||
function onStationSelected(event, station) {
|
||||
navigate(`/station/sncf/${station.slug}/`)
|
||||
function onStationSelected(event, stop) {
|
||||
navigate(`/station/sncf/${stop.id}/`)
|
||||
}
|
||||
|
||||
return <>
|
||||
@ -13,7 +13,7 @@ function Home() {
|
||||
<h2>
|
||||
Choisissez une gare dont vous désirez connaître le tableau des prochains départs et arrivées :
|
||||
</h2>
|
||||
<AutocompleteStation onChange={onStationSelected} />
|
||||
<AutocompleteStop onChange={onStationSelected} />
|
||||
</>
|
||||
}
|
||||
|
||||
|
@ -5,14 +5,14 @@ import {Box, Button, FormLabel} from "@mui/material";
|
||||
import {DatePicker, TimePicker} from "@mui/x-date-pickers";
|
||||
import dayjs from "dayjs";
|
||||
import {useQuery, useQueryClient} from "@tanstack/react-query";
|
||||
import AutocompleteStation from "./AutocompleteStation";
|
||||
import AutocompleteStop from "./AutocompleteStop";
|
||||
|
||||
function DateTimeSelector({station, date, time}) {
|
||||
function DateTimeSelector({stop, date, time}) {
|
||||
const navigate = useNavigate()
|
||||
|
||||
function onStationSelected(event, station) {
|
||||
if (station !== null)
|
||||
navigate(`/station/sncf/${station.slug}/`)
|
||||
function onStationSelected(event, stop) {
|
||||
if (stop !== null)
|
||||
navigate(`/station/sncf/${stop.id}/`)
|
||||
}
|
||||
|
||||
return <>
|
||||
@ -20,7 +20,7 @@ function DateTimeSelector({station, date, time}) {
|
||||
<FormLabel>
|
||||
Changer la gare recherchée :
|
||||
</FormLabel>
|
||||
<AutocompleteStation onChange={onStationSelected} />
|
||||
<AutocompleteStop onChange={onStationSelected} />
|
||||
<FormLabel>
|
||||
Modifier la date et l'heure de recherche :
|
||||
</FormLabel>
|
||||
@ -32,7 +32,7 @@ function DateTimeSelector({station, date, time}) {
|
||||
}
|
||||
|
||||
function Station() {
|
||||
let {theme, stationSlug} = useParams()
|
||||
let {stopId, theme} = useParams()
|
||||
let [searchParams, _setSearchParams] = useSearchParams()
|
||||
const now = new Date()
|
||||
let dateNow = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`
|
||||
@ -41,13 +41,13 @@ function Station() {
|
||||
let [time, setTime] = useState(searchParams.get('time') || timeNow)
|
||||
|
||||
useQueryClient()
|
||||
const stationQuery = useQuery({
|
||||
queryKey: ['station', stationSlug],
|
||||
queryFn: () => fetch(`/api/core/station/${stationSlug}/`)
|
||||
const stopQuery = useQuery({
|
||||
queryKey: ['stop', stopId],
|
||||
queryFn: () => fetch(`/api/gtfs/stop/${stopId}/`)
|
||||
.then(response => response.json()),
|
||||
enabled: !!stationSlug,
|
||||
enabled: !!stopId,
|
||||
})
|
||||
const station = stationQuery.data ?? {name: "Chargement…"}
|
||||
const stop = stopQuery.data ?? {name: "Chargement…"}
|
||||
|
||||
if (time === timeNow) {
|
||||
setInterval(() => {
|
||||
@ -62,13 +62,13 @@ function Station() {
|
||||
return (
|
||||
<div className="Station">
|
||||
<header className="App-header">
|
||||
<h1>Horaires en gare de {station.name}</h1>
|
||||
<h1>Horaires en gare de {stop.name}</h1>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<DateTimeSelector station={station} date={date} time={time} />
|
||||
<TrainsTable station={station} date={date} time={time} tableType="departures" />
|
||||
<TrainsTable station={station} date={date} time={time} tableType="arrivals" />
|
||||
<DateTimeSelector stop={stop} date={date} time={time} />
|
||||
<TrainsTable stop={stop} date={date} time={time} tableType="departures" />
|
||||
<TrainsTable stop={stop} date={date} time={time} tableType="arrivals" />
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
|
@ -26,12 +26,12 @@ const StyledTableRow = styled(TableRow)(({ theme, tabletype }) => ({
|
||||
},
|
||||
}));
|
||||
|
||||
function TrainsTable({station, date, time, tableType}) {
|
||||
function TrainsTable({stop, date, time, tableType}) {
|
||||
return <>
|
||||
<TableContainer>
|
||||
<Table>
|
||||
<TrainsTableHeader tableType={tableType} />
|
||||
<TrainsTableBody station={station} date={date} time={time} tableType={tableType} />
|
||||
<TrainsTableBody stop={stop} date={date} time={time} tableType={tableType} />
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</>
|
||||
@ -49,7 +49,7 @@ function TrainsTableHeader({tableType}) {
|
||||
</>
|
||||
}
|
||||
|
||||
function TrainsTableBody({station, date, time, tableType}) {
|
||||
function TrainsTableBody({stop, date, time, tableType}) {
|
||||
const filterTime = useCallback((train) => {
|
||||
if (tableType === "departures")
|
||||
return `${train.departure_date}T${train.departure_time_24h}` >= `${date}T${time}`
|
||||
@ -58,16 +58,16 @@ function TrainsTableBody({station, date, time, tableType}) {
|
||||
}, [date, time, tableType])
|
||||
|
||||
const updateTrains = useCallback(() => {
|
||||
return fetch(`/api/station/next_${tableType}/?station_slug=${station.slug}&date=${date}&time=${time}&offset=${0}&limit=${20}`)
|
||||
return fetch(`/api/station/next_${tableType}/?stop_id=${stop.id}&date=${date}&time=${time}&offset=${0}&limit=${20}`)
|
||||
.then(response => response.json())
|
||||
.then(data => data.results)
|
||||
.then(data => [...data])
|
||||
}, [station.id, date, time, tableType])
|
||||
}, [stop.id, date, time, tableType])
|
||||
|
||||
const trainsQuery = useQuery({
|
||||
queryKey: ['trains', station.id, tableType],
|
||||
queryKey: ['trains', stop.id, tableType],
|
||||
queryFn: updateTrains,
|
||||
enabled: !!station.id,
|
||||
enabled: !!stop.id,
|
||||
})
|
||||
const trains = useMemo(() => trainsQuery.data ?? [], [trainsQuery.data])
|
||||
|
||||
@ -114,7 +114,7 @@ function TrainRow({train, tableType, date, time}) {
|
||||
|
||||
const stopTimesQuery = useQuery({
|
||||
queryKey: ['stop_times', trip.id],
|
||||
queryFn: () => fetch(`/api/gtfs/stop_time/?${new URLSearchParams({trip: trip.id, order: 'stop_sequence', limit: 1000})}`)
|
||||
queryFn: () => fetch(`/api/gtfs/stop_time/?trip=${trip.id}&order=stop_sequence&limit=1000`)
|
||||
.then(response => response.json())
|
||||
.then(data => data.results),
|
||||
enabled: !!trip.id,
|
||||
|
@ -1,18 +1,9 @@
|
||||
from rest_framework import serializers
|
||||
|
||||
from trainvel.core.models import Station
|
||||
from trainvel.gtfs.models import Agency, Stop, Route, Trip, StopTime, Calendar, CalendarDate, \
|
||||
Transfer, FeedInfo, TripUpdate, StopTimeUpdate
|
||||
|
||||
|
||||
class StationSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Station
|
||||
lookup_field = 'slug'
|
||||
fields = ('id', 'slug', 'name', 'uic', 'uic8_sncf', 'latitude', 'longitude', 'country',
|
||||
'country_hint', 'main_station_hint',)
|
||||
|
||||
|
||||
class AgencySerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Agency
|
||||
|
@ -10,28 +10,13 @@ from rest_framework.filters import OrderingFilter, SearchFilter
|
||||
|
||||
from trainvel.api.serializers import AgencySerializer, StopSerializer, RouteSerializer, TripSerializer, \
|
||||
StopTimeSerializer, CalendarSerializer, CalendarDateSerializer, TransferSerializer, \
|
||||
FeedInfoSerializer, TripUpdateSerializer, StopTimeUpdateSerializer, StationSerializer
|
||||
from trainvel.core.models import Station
|
||||
from trainvel.gtfs.models import Agency, Calendar, CalendarDate, FeedInfo, GTFSFeed, Route, Stop, StopTime, \
|
||||
StopTimeUpdate, \
|
||||
Transfer, Trip, TripUpdate, PickupType
|
||||
FeedInfoSerializer, TripUpdateSerializer, StopTimeUpdateSerializer
|
||||
from trainvel.gtfs.models import Agency, Calendar, CalendarDate, FeedInfo, GTFSFeed, Route, Stop, StopTime, StopTimeUpdate, \
|
||||
Transfer, Trip, TripUpdate
|
||||
|
||||
CACHE_CONTROL = cache_control(max_age=30)
|
||||
CACHE_CONTROL = cache_control(max_age=7200)
|
||||
LAST_MODIFIED = last_modified(lambda *args, **kwargs: GTFSFeed.objects.order_by('-last_modified').first().last_modified)
|
||||
LOOKUP_VALUE_REGEX = r"[\w.: |+-]+"
|
||||
|
||||
|
||||
class StationViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
queryset = Station.objects.filter(is_suggestable=True)
|
||||
serializer_class = StationSerializer
|
||||
filter_backends = [DjangoFilterBackend, SearchFilter]
|
||||
filterset_fields = '__all__'
|
||||
search_fields = ['name', 'slug',
|
||||
'info_de', 'info_en', 'info_es', 'info_fr', 'info_it', 'info_nb', 'info_nl', 'info_cs',
|
||||
'info_da', 'info_hu', 'info_ja', 'info_ko', 'info_pl', 'info_pt', 'info_ru', 'info_sv',
|
||||
'info_tr', 'info_zh', ]
|
||||
lookup_field = 'slug'
|
||||
lookup_value_regex = LOOKUP_VALUE_REGEX
|
||||
LOOKUP_VALUE_REGEX = r"[\w.: |-]+"
|
||||
|
||||
|
||||
@method_decorator(name='list', decorator=[CACHE_CONTROL, LAST_MODIFIED])
|
||||
@ -150,7 +135,8 @@ class NextDeparturesViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
def get_queryset(self):
|
||||
now = datetime.now()
|
||||
|
||||
station_slug = self.request.query_params.get('station_slug', None)
|
||||
stop_id = self.request.query_params.get('stop_id', None)
|
||||
stop_name = self.request.query_params.get('stop_name', None)
|
||||
query_date = date.fromisoformat(self.request.query_params.get('date', now.date().isoformat()))
|
||||
query_time = self.request.query_params.get('time', now.time().isoformat(timespec='seconds'))
|
||||
query_time = timedelta(seconds=int(query_time[:2]) * 3600
|
||||
@ -162,10 +148,16 @@ class NextDeparturesViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
tomorrow = query_date + timedelta(days=1)
|
||||
|
||||
stop_filter = Q(stop__location_type=0)
|
||||
if station_slug:
|
||||
station = Station.objects.get(is_suggestable=True, slug=station_slug)
|
||||
near_stops = station.get_near_stops()
|
||||
stop_filter = Q(stop_id__in=near_stops.values_list('id', flat=True))
|
||||
if stop_id:
|
||||
stop = Stop.objects.get(id=stop_id)
|
||||
stops = Stop.objects.filter(Q(id=stop_id)
|
||||
| Q(parent_station=stop_id))
|
||||
if stop.location_type == 0 and stop.parent_station_id is not None:
|
||||
stops |= Stop.objects.filter(parent_station=stop.parent_station_id)
|
||||
stop_filter = Q(stop__in=stops.values_list('id', flat=True))
|
||||
elif stop_name:
|
||||
stops = Stop.objects.filter(name__iexact=stop_name).values_list('id', flat=True)
|
||||
stop_filter = Q(stop__in=stops)
|
||||
|
||||
def calendar_filter(d: date):
|
||||
return Q(trip__service_id__in=CalendarDate.objects.filter(date=d, exception_type=1)
|
||||
@ -197,7 +189,7 @@ class NextDeparturesViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
qs_today = StopTime.objects.filter(stop_filter) \
|
||||
.annotate(departure_time_real=departure_time_real(query_date)) \
|
||||
.filter(departure_time_real__gte=query_time) \
|
||||
.filter(Q(pickup_type=PickupType.REGULAR) | canceled_filter(query_date)) \
|
||||
.filter(Q(pickup_type=0) | canceled_filter(query_date)) \
|
||||
.filter(calendar_filter(query_date)) \
|
||||
.annotate(departure_date=Value(query_date)) \
|
||||
.annotate(departure_time_24h=F('departure_time'))
|
||||
@ -229,7 +221,8 @@ class NextArrivalsViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
def get_queryset(self):
|
||||
now = datetime.now()
|
||||
|
||||
station_slug = self.request.query_params.get('station_slug', None)
|
||||
stop_id = self.request.query_params.get('stop_id', None)
|
||||
stop_name = self.request.query_params.get('stop_name', None)
|
||||
query_date = date.fromisoformat(self.request.query_params.get('date', now.date().isoformat()))
|
||||
query_time = self.request.query_params.get('time', now.time().isoformat(timespec='seconds'))
|
||||
query_time = timedelta(seconds=int(query_time[:2]) * 3600
|
||||
@ -242,10 +235,16 @@ class NextArrivalsViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
tomorrow = query_date + timedelta(days=1)
|
||||
|
||||
stop_filter = Q(stop__location_type=0)
|
||||
if station_slug:
|
||||
station = Station.objects.get(is_suggestable=True, slug=station_slug)
|
||||
near_stops = station.get_near_stops()
|
||||
stop_filter = Q(stop_id__in=near_stops.values_list('id', flat=True))
|
||||
if stop_id:
|
||||
stop = Stop.objects.get(id=stop_id)
|
||||
stops = Stop.objects.filter(Q(id=stop_id)
|
||||
| Q(parent_station=stop_id))
|
||||
if stop.location_type == 0 and stop.parent_station_id is not None:
|
||||
stops |= Stop.objects.filter(parent_station=stop.parent_station_id)
|
||||
stop_filter = Q(stop__in=stops.values_list('id', flat=True))
|
||||
elif stop_name:
|
||||
stops = Stop.objects.filter(name__iexact=stop_name).values_list('id', flat=True)
|
||||
stop_filter = Q(stop__in=stops)
|
||||
|
||||
def calendar_filter(d: date):
|
||||
return Q(trip__service_id__in=CalendarDate.objects.filter(date=d, exception_type=1)
|
||||
|
@ -1,23 +0,0 @@
|
||||
from django.contrib import admin
|
||||
|
||||
from trainvel.core.models import Station
|
||||
|
||||
|
||||
class StationInline(admin.TabularInline):
|
||||
model = Station
|
||||
extra = 0
|
||||
autocomplete_fields = ('parent_station', 'same_as',)
|
||||
show_change_link = True
|
||||
ordering = ('name',)
|
||||
readonly_fields = ('id',)
|
||||
fk_name = 'parent_station'
|
||||
|
||||
|
||||
@admin.register(Station)
|
||||
class StationAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'country', 'uic', 'latitude', 'longitude',)
|
||||
list_filter = ('country', 'is_city', 'is_main_station', 'is_airport', 'is_suggestable',
|
||||
'country_hint', 'main_station_hint',)
|
||||
search_fields = ('name', 'slug',)
|
||||
autocomplete_fields = ('parent_station', 'same_as',)
|
||||
inlines = [StationInline]
|
@ -1,8 +0,0 @@
|
||||
from django.apps import AppConfig
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
||||
class CoreConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "trainvel.core"
|
||||
verbose_name = _("Trainvel - Core")
|
@ -1,325 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: 1.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-05-09 22:04+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Emmy D'Anello <ynerant@emy.lu>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#: trainvel/core/apps.py:8
|
||||
msgid "Trainvel - Core"
|
||||
msgstr "Trainvel - Cœur"
|
||||
|
||||
#: trainvel/core/models.py:15
|
||||
msgid "name"
|
||||
msgstr "nom"
|
||||
|
||||
#: trainvel/core/models.py:20
|
||||
msgid "slug"
|
||||
msgstr "slug"
|
||||
|
||||
#: trainvel/core/models.py:24
|
||||
msgid "UIC"
|
||||
msgstr "UIC"
|
||||
|
||||
#: trainvel/core/models.py:31
|
||||
msgid "UIC8 SNCF"
|
||||
msgstr "UIC8 SNCF"
|
||||
|
||||
#: trainvel/core/models.py:38
|
||||
msgid "latitude"
|
||||
msgstr "latitude"
|
||||
|
||||
#: trainvel/core/models.py:45
|
||||
msgid "longitude"
|
||||
msgstr "longitude"
|
||||
|
||||
#: trainvel/core/models.py:54
|
||||
msgid "parent station"
|
||||
msgstr "gare parente"
|
||||
|
||||
#: trainvel/core/models.py:63
|
||||
msgid "country"
|
||||
msgstr "pays"
|
||||
|
||||
#: trainvel/core/models.py:69
|
||||
msgid "timezone"
|
||||
msgstr "fuseau horaire"
|
||||
|
||||
#: trainvel/core/models.py:73
|
||||
msgid "is city"
|
||||
msgstr "est une ville"
|
||||
|
||||
#: trainvel/core/models.py:77
|
||||
msgid "is main station"
|
||||
msgstr "est une gare principale"
|
||||
|
||||
#: trainvel/core/models.py:81
|
||||
msgid "is airport"
|
||||
msgstr "est un aéroport"
|
||||
|
||||
#: trainvel/core/models.py:85
|
||||
msgid "is suggestable"
|
||||
msgstr "est suggérable"
|
||||
|
||||
#: trainvel/core/models.py:89
|
||||
msgid "country hint"
|
||||
msgstr "indice de pays"
|
||||
|
||||
#: trainvel/core/models.py:93
|
||||
msgid "main station hint"
|
||||
msgstr "indice de gare principale"
|
||||
|
||||
#: trainvel/core/models.py:98
|
||||
msgid "SNCF ID"
|
||||
msgstr "ID SNCF"
|
||||
|
||||
#: trainvel/core/models.py:106
|
||||
msgid "SNCF TVS ID"
|
||||
msgstr "ID SNCF TVS"
|
||||
|
||||
#: trainvel/core/models.py:113
|
||||
msgid "SNCF is enabled"
|
||||
msgstr "SNCF est activé"
|
||||
|
||||
#: trainvel/core/models.py:118
|
||||
msgid "Entur ID"
|
||||
msgstr "ID Entur"
|
||||
|
||||
#: trainvel/core/models.py:125
|
||||
msgid "Entur is enabled"
|
||||
msgstr "Entur est activé"
|
||||
|
||||
#: trainvel/core/models.py:129
|
||||
msgid "DB ID"
|
||||
msgstr "ID DB"
|
||||
|
||||
#: trainvel/core/models.py:136
|
||||
msgid "DB is enabled"
|
||||
msgstr "DB est activé"
|
||||
|
||||
#: trainvel/core/models.py:141
|
||||
msgid "Busbud ID"
|
||||
msgstr "ID Busbud"
|
||||
|
||||
#: trainvel/core/models.py:148
|
||||
msgid "Busbud is enabled"
|
||||
msgstr "Busbud est activé"
|
||||
|
||||
#: trainvel/core/models.py:153
|
||||
msgid "distribusion ID"
|
||||
msgstr "ID distribusion"
|
||||
|
||||
#: trainvel/core/models.py:160
|
||||
msgid "distribusion is enabled"
|
||||
msgstr "distribusion est activé"
|
||||
|
||||
#: trainvel/core/models.py:164
|
||||
msgid "Flixbus ID"
|
||||
msgstr "ID Flixbus"
|
||||
|
||||
#: trainvel/core/models.py:171
|
||||
msgid "Flixbus is enabled"
|
||||
msgstr "Flixbus est activé"
|
||||
|
||||
#: trainvel/core/models.py:175
|
||||
msgid "CFF ID"
|
||||
msgstr "ID CFF"
|
||||
|
||||
#: trainvel/core/models.py:182
|
||||
msgid "CFF is enabled"
|
||||
msgstr "CFF est activé"
|
||||
|
||||
#: trainvel/core/models.py:187
|
||||
msgid "Leo Express ID"
|
||||
msgstr "ID Leo Express"
|
||||
|
||||
#: trainvel/core/models.py:194
|
||||
msgid "Leo Express is enabled"
|
||||
msgstr "Leo Express est activé"
|
||||
|
||||
#: trainvel/core/models.py:198
|
||||
msgid "ÖBB ID"
|
||||
msgstr "ID ÖBB"
|
||||
|
||||
#: trainvel/core/models.py:205
|
||||
msgid "ÖBB is enabled"
|
||||
msgstr "ÖBB est activé"
|
||||
|
||||
#: trainvel/core/models.py:210
|
||||
msgid "Ouigo ID"
|
||||
msgstr "ID Ouigo"
|
||||
|
||||
#: trainvel/core/models.py:217
|
||||
msgid "Ouigo is enabled"
|
||||
msgstr "Ouigo est activé"
|
||||
|
||||
#: trainvel/core/models.py:221
|
||||
msgid "Trenitalia ID"
|
||||
msgstr "ID Trenitalia"
|
||||
|
||||
#: trainvel/core/models.py:228
|
||||
msgid "Trenitalia is enabled"
|
||||
msgstr "Trenitalia est activé"
|
||||
|
||||
#: trainvel/core/models.py:233
|
||||
msgid "Trenitalia RTVT ID"
|
||||
msgstr "ID Trenitalia RTVT"
|
||||
|
||||
#: trainvel/core/models.py:241
|
||||
msgid "Trenord ID"
|
||||
msgstr "ID Trenord"
|
||||
|
||||
#: trainvel/core/models.py:249
|
||||
msgid "NTV RTIV ID"
|
||||
msgstr "ID NTV RTIV"
|
||||
|
||||
#: trainvel/core/models.py:257
|
||||
msgid "NTV ID"
|
||||
msgstr "ID NTV"
|
||||
|
||||
#: trainvel/core/models.py:264
|
||||
msgid "NTV is enabled"
|
||||
msgstr "NTV est activé"
|
||||
|
||||
#: trainvel/core/models.py:269
|
||||
msgid "HKX ID"
|
||||
msgstr "ID HKX"
|
||||
|
||||
#: trainvel/core/models.py:276
|
||||
msgid "HKX is enabled"
|
||||
msgstr "HKX est activé"
|
||||
|
||||
#: trainvel/core/models.py:280
|
||||
msgid "Renfe ID"
|
||||
msgstr "ID Renfe"
|
||||
|
||||
#: trainvel/core/models.py:287
|
||||
msgid "Renfe is enabled"
|
||||
msgstr "Renfe est activé"
|
||||
|
||||
#: trainvel/core/models.py:292
|
||||
msgid "ATOC ID"
|
||||
msgstr "ID ATOC"
|
||||
|
||||
#: trainvel/core/models.py:299
|
||||
msgid "ATOC is enabled"
|
||||
msgstr "ATOC est activé"
|
||||
|
||||
#: trainvel/core/models.py:304
|
||||
msgid "Benerail ID"
|
||||
msgstr "ID Benerail"
|
||||
|
||||
#: trainvel/core/models.py:311
|
||||
msgid "Benerail is enabled"
|
||||
msgstr "Benerail est activé"
|
||||
|
||||
#: trainvel/core/models.py:316
|
||||
msgid "Westbahn ID"
|
||||
msgstr "ID Westbahn"
|
||||
|
||||
#: trainvel/core/models.py:323
|
||||
msgid "Westbahn is enabled"
|
||||
msgstr "Westbahn est activé"
|
||||
|
||||
#: trainvel/core/models.py:327
|
||||
msgid "SNCF self-service machine"
|
||||
msgstr "Automate self-service SNCF"
|
||||
|
||||
#: trainvel/core/models.py:333
|
||||
msgid "same as"
|
||||
msgstr "identique à"
|
||||
|
||||
#: trainvel/core/models.py:342
|
||||
msgid "info (DE)"
|
||||
msgstr "info (DE)"
|
||||
|
||||
#: trainvel/core/models.py:350
|
||||
msgid "info (EN)"
|
||||
msgstr "info (EN)"
|
||||
|
||||
#: trainvel/core/models.py:358
|
||||
msgid "info (ES)"
|
||||
msgstr "info (ES)"
|
||||
|
||||
#: trainvel/core/models.py:366
|
||||
msgid "info (FR)"
|
||||
msgstr "info (FR)"
|
||||
|
||||
#: trainvel/core/models.py:374
|
||||
msgid "info (IT)"
|
||||
msgstr "info (IT)"
|
||||
|
||||
#: trainvel/core/models.py:382
|
||||
msgid "info (NB)"
|
||||
msgstr "info (NB)"
|
||||
|
||||
#: trainvel/core/models.py:390
|
||||
msgid "info (NL)"
|
||||
msgstr "info (NL)"
|
||||
|
||||
#: trainvel/core/models.py:398
|
||||
msgid "info (CS)"
|
||||
msgstr "info (CS)"
|
||||
|
||||
#: trainvel/core/models.py:406
|
||||
msgid "info (DA)"
|
||||
msgstr "info (DA)"
|
||||
|
||||
#: trainvel/core/models.py:414
|
||||
msgid "info (HU)"
|
||||
msgstr "info (HU)"
|
||||
|
||||
#: trainvel/core/models.py:422
|
||||
msgid "info (JA)"
|
||||
msgstr "info (JA)"
|
||||
|
||||
#: trainvel/core/models.py:430
|
||||
msgid "info (KO)"
|
||||
msgstr "info (KO)"
|
||||
|
||||
#: trainvel/core/models.py:438
|
||||
msgid "info (PL)"
|
||||
msgstr "info (PL)"
|
||||
|
||||
#: trainvel/core/models.py:446
|
||||
msgid "info (PT)"
|
||||
msgstr "info (PT)"
|
||||
|
||||
#: trainvel/core/models.py:454
|
||||
msgid "info (RU)"
|
||||
msgstr "info (RU)"
|
||||
|
||||
#: trainvel/core/models.py:462
|
||||
msgid "info (SV)"
|
||||
msgstr "info (SV)"
|
||||
|
||||
#: trainvel/core/models.py:470
|
||||
msgid "info (TR)"
|
||||
msgstr "info (TR)"
|
||||
|
||||
#: trainvel/core/models.py:478
|
||||
msgid "info (ZH)"
|
||||
msgstr "info (ZH)"
|
||||
|
||||
#: trainvel/core/models.py:486
|
||||
msgid "normalized code (Trainline)"
|
||||
msgstr "code normalisé (Trainline)"
|
||||
|
||||
#: trainvel/core/models.py:491
|
||||
msgid "IATA airport code"
|
||||
msgstr "code aéroport IATA"
|
||||
|
||||
#: trainvel/core/models.py:501
|
||||
msgid "station"
|
||||
msgstr "gare"
|
||||
|
||||
#: trainvel/core/models.py:502
|
||||
msgid "stations"
|
||||
msgstr "gares"
|
@ -1,33 +0,0 @@
|
||||
import csv
|
||||
|
||||
import requests
|
||||
from django.core.management import BaseCommand
|
||||
from tqdm import tqdm
|
||||
|
||||
from trainvel.core.models import Station
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
def handle(self, *args, **options):
|
||||
def convert_value(value: str) -> str:
|
||||
return True if value == 't' else False if value == 'f' else (value or None)
|
||||
|
||||
stations, stations_without_fk = [], []
|
||||
|
||||
STATIONS_URL = "https://raw.githubusercontent.com/trainline-eu/stations/master/stations.csv"
|
||||
with requests.get(STATIONS_URL, stream=True) as resp:
|
||||
for row in csv.DictReader(tqdm(resp.iter_lines(decode_unicode=True)), delimiter=';'):
|
||||
row: dict
|
||||
values = {k.replace(':', '_').replace('normalised_code', 'normalized_code_trainline')
|
||||
.replace('same_as', 'same_as_id'): convert_value(v)
|
||||
for k, v in row.items()}
|
||||
values_without_fk = values.copy()
|
||||
del values_without_fk['same_as_id']
|
||||
del values_without_fk['parent_station_id']
|
||||
stations.append(Station(**values))
|
||||
stations_without_fk.append(Station(**values_without_fk))
|
||||
|
||||
Station.objects.bulk_create(stations_without_fk, update_conflicts=True, unique_fields=['id'],
|
||||
update_fields=[k for k in values_without_fk.keys() if k != 'id'])
|
||||
Station.objects.bulk_create(stations, update_conflicts=True, unique_fields=['id'],
|
||||
update_fields=['same_as_id', 'parent_station_id'])
|
@ -1,603 +0,0 @@
|
||||
# Generated by Django 5.0.1 on 2024-05-09 22:15
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = []
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="Station",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("name", models.CharField(max_length=255, verbose_name="name")),
|
||||
("slug", models.SlugField(max_length=255, verbose_name="slug")),
|
||||
(
|
||||
"uic",
|
||||
models.IntegerField(
|
||||
blank=True, default=None, null=True, verbose_name="UIC"
|
||||
),
|
||||
),
|
||||
(
|
||||
"uic8_sncf",
|
||||
models.IntegerField(
|
||||
blank=True, default=None, null=True, verbose_name="UIC8 SNCF"
|
||||
),
|
||||
),
|
||||
(
|
||||
"latitude",
|
||||
models.FloatField(
|
||||
blank=True, default=None, null=True, verbose_name="latitude"
|
||||
),
|
||||
),
|
||||
(
|
||||
"longitude",
|
||||
models.FloatField(
|
||||
blank=True, default=None, null=True, verbose_name="longitude"
|
||||
),
|
||||
),
|
||||
(
|
||||
"country",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("AL", "Albania"),
|
||||
("AD", "Andorra"),
|
||||
("AM", "Armenia"),
|
||||
("AT", "Austria"),
|
||||
("AZ", "Azerbaijan"),
|
||||
("BE", "Belgium"),
|
||||
("BA", "Bosnia and Herzegovina"),
|
||||
("BG", "Bulgaria"),
|
||||
("HR", "Croatia"),
|
||||
("CY", "Cyprus"),
|
||||
("CZ", "Czech Republic"),
|
||||
("DK", "Denmark"),
|
||||
("EE", "Estonia"),
|
||||
("FI", "Finland"),
|
||||
("FR", "France"),
|
||||
("GE", "Georgia"),
|
||||
("DE", "Germany"),
|
||||
("GR", "Greece"),
|
||||
("HU", "Hungary"),
|
||||
("IS", "Iceland"),
|
||||
("IE", "Ireland"),
|
||||
("IT", "Italy"),
|
||||
("LV", "Latvia"),
|
||||
("LI", "Liechtenstein"),
|
||||
("LT", "Lithuania"),
|
||||
("LU", "Luxembourg"),
|
||||
("MT", "Malta"),
|
||||
("MD", "Moldova"),
|
||||
("MC", "Monaco"),
|
||||
("ME", "Montenegro"),
|
||||
("NL", "Netherlands"),
|
||||
("MK", "North Macedonia"),
|
||||
("NO", "Norway"),
|
||||
("PL", "Poland"),
|
||||
("PT", "Portugal"),
|
||||
("RO", "Romania"),
|
||||
("SM", "San Marino"),
|
||||
("RS", "Serbia"),
|
||||
("SK", "Slovakia"),
|
||||
("SI", "Slovenia"),
|
||||
("ES", "Spain"),
|
||||
("SE", "Sweden"),
|
||||
("CH", "Switzerland"),
|
||||
("TR", "Turkey"),
|
||||
("GB", "United Kingdom"),
|
||||
("UA", "Ukraine"),
|
||||
],
|
||||
max_length=255,
|
||||
verbose_name="country",
|
||||
),
|
||||
),
|
||||
(
|
||||
"time_zone",
|
||||
models.CharField(max_length=255, verbose_name="timezone"),
|
||||
),
|
||||
("is_city", models.BooleanField(verbose_name="is city")),
|
||||
(
|
||||
"is_main_station",
|
||||
models.BooleanField(verbose_name="is main station"),
|
||||
),
|
||||
("is_airport", models.BooleanField(verbose_name="is airport")),
|
||||
("is_suggestable", models.BooleanField(verbose_name="is suggestable")),
|
||||
("country_hint", models.BooleanField(verbose_name="country hint")),
|
||||
(
|
||||
"main_station_hint",
|
||||
models.BooleanField(verbose_name="main station hint"),
|
||||
),
|
||||
(
|
||||
"sncf_id",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=5,
|
||||
null=True,
|
||||
verbose_name="SNCF ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"sncf_tvs_id",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=3,
|
||||
null=True,
|
||||
verbose_name="SNCF TVS ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"sncf_is_enabled",
|
||||
models.BooleanField(verbose_name="SNCF is enabled"),
|
||||
),
|
||||
(
|
||||
"entur_id",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="Entur ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"entur_is_enabled",
|
||||
models.BooleanField(verbose_name="Entur is enabled"),
|
||||
),
|
||||
(
|
||||
"db_id",
|
||||
models.IntegerField(
|
||||
blank=True, default=None, null=True, verbose_name="DB ID"
|
||||
),
|
||||
),
|
||||
("db_is_enabled", models.BooleanField(verbose_name="DB is enabled")),
|
||||
(
|
||||
"busbud_id",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="Busbud ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"busbud_is_enabled",
|
||||
models.BooleanField(verbose_name="Busbud is enabled"),
|
||||
),
|
||||
(
|
||||
"distribusion_id",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="distribusion ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"distribusion_is_enabled",
|
||||
models.BooleanField(verbose_name="distribusion is enabled"),
|
||||
),
|
||||
(
|
||||
"flixbus_id",
|
||||
models.IntegerField(
|
||||
blank=True, default=None, null=True, verbose_name="Flixbus ID"
|
||||
),
|
||||
),
|
||||
(
|
||||
"flixbus_is_enabled",
|
||||
models.BooleanField(verbose_name="Flixbus is enabled"),
|
||||
),
|
||||
(
|
||||
"cff_id",
|
||||
models.IntegerField(
|
||||
blank=True, default=None, null=True, verbose_name="CFF ID"
|
||||
),
|
||||
),
|
||||
("cff_is_enabled", models.BooleanField(verbose_name="CFF is enabled")),
|
||||
(
|
||||
"leoexpress_id",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="Leo Express ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"leoexpress_is_enabled",
|
||||
models.BooleanField(verbose_name="Leo Express is enabled"),
|
||||
),
|
||||
(
|
||||
"obb_id",
|
||||
models.IntegerField(
|
||||
blank=True, default=None, null=True, verbose_name="ÖBB ID"
|
||||
),
|
||||
),
|
||||
("obb_is_enabled", models.BooleanField(verbose_name="ÖBB is enabled")),
|
||||
(
|
||||
"ouigo_id",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="Ouigo ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"ouigo_is_enabled",
|
||||
models.BooleanField(verbose_name="Ouigo is enabled"),
|
||||
),
|
||||
(
|
||||
"trenitalia_id",
|
||||
models.IntegerField(
|
||||
blank=True,
|
||||
default=None,
|
||||
null=True,
|
||||
verbose_name="Trenitalia ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"trenitalia_is_enabled",
|
||||
models.BooleanField(verbose_name="Trenitalia is enabled"),
|
||||
),
|
||||
(
|
||||
"trenitalia_rtvt_id",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="Trenitalia RTVT ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"trenord_id",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="Trenord ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"ntv_rtiv_id",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="NTV RTIV ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"ntv_id",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="NTV ID",
|
||||
),
|
||||
),
|
||||
("ntv_is_enabled", models.BooleanField(verbose_name="NTV is enabled")),
|
||||
(
|
||||
"hkx_id",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="HKX ID",
|
||||
),
|
||||
),
|
||||
("hkx_is_enabled", models.BooleanField(verbose_name="HKX is enabled")),
|
||||
(
|
||||
"renfe_id",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="Renfe ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"renfe_is_enabled",
|
||||
models.BooleanField(verbose_name="Renfe is enabled"),
|
||||
),
|
||||
(
|
||||
"atoc_id",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="ATOC ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"atoc_is_enabled",
|
||||
models.BooleanField(verbose_name="ATOC is enabled"),
|
||||
),
|
||||
(
|
||||
"benerail_id",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="Benerail ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"benerail_is_enabled",
|
||||
models.BooleanField(verbose_name="Benerail is enabled"),
|
||||
),
|
||||
(
|
||||
"westbahn_id",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="Westbahn ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"westbahn_is_enabled",
|
||||
models.BooleanField(verbose_name="Westbahn is enabled"),
|
||||
),
|
||||
(
|
||||
"sncf_self_service_machine",
|
||||
models.BooleanField(verbose_name="SNCF self-service machine"),
|
||||
),
|
||||
(
|
||||
"info_de",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="info (DE)",
|
||||
),
|
||||
),
|
||||
(
|
||||
"info_en",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="info (EN)",
|
||||
),
|
||||
),
|
||||
(
|
||||
"info_es",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="info (ES)",
|
||||
),
|
||||
),
|
||||
(
|
||||
"info_fr",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="info (FR)",
|
||||
),
|
||||
),
|
||||
(
|
||||
"info_it",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="info (IT)",
|
||||
),
|
||||
),
|
||||
(
|
||||
"info_nb",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="info (NB)",
|
||||
),
|
||||
),
|
||||
(
|
||||
"info_nl",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="info (NL)",
|
||||
),
|
||||
),
|
||||
(
|
||||
"info_cs",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="info (CS)",
|
||||
),
|
||||
),
|
||||
(
|
||||
"info_da",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="info (DA)",
|
||||
),
|
||||
),
|
||||
(
|
||||
"info_hu",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="info (HU)",
|
||||
),
|
||||
),
|
||||
(
|
||||
"info_ja",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="info (JA)",
|
||||
),
|
||||
),
|
||||
(
|
||||
"info_ko",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="info (KO)",
|
||||
),
|
||||
),
|
||||
(
|
||||
"info_pl",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="info (PL)",
|
||||
),
|
||||
),
|
||||
(
|
||||
"info_pt",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="info (PT)",
|
||||
),
|
||||
),
|
||||
(
|
||||
"info_ru",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="info (RU)",
|
||||
),
|
||||
),
|
||||
(
|
||||
"info_sv",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="info (SV)",
|
||||
),
|
||||
),
|
||||
(
|
||||
"info_tr",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="info (TR)",
|
||||
),
|
||||
),
|
||||
(
|
||||
"info_zh",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="info (ZH)",
|
||||
),
|
||||
),
|
||||
(
|
||||
"normalized_code_trainline",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="normalized code (Trainline)",
|
||||
),
|
||||
),
|
||||
(
|
||||
"iata_airport_code",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="IATA airport code",
|
||||
),
|
||||
),
|
||||
(
|
||||
"parent_station",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
default=None,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="children",
|
||||
to="core.station",
|
||||
verbose_name="parent station",
|
||||
),
|
||||
),
|
||||
(
|
||||
"same_as",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
default=None,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="same_as_other",
|
||||
to="core.station",
|
||||
verbose_name="same as",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "station",
|
||||
"verbose_name_plural": "stations",
|
||||
},
|
||||
),
|
||||
]
|
@ -1,519 +0,0 @@
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
from django.db.models import F, QuerySet
|
||||
from django.db.models.functions import ACos, Sin, Radians, Cos
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from trainvel.gtfs.models import Country, Stop
|
||||
|
||||
|
||||
class Station(models.Model):
|
||||
"""
|
||||
Describes the content of the stations CSV file generated by Trainline.
|
||||
The CSV file can be found at https://raw.githubusercontent.com/trainline-eu/stations/master/stations.csv
|
||||
"""
|
||||
|
||||
name = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("name"),
|
||||
)
|
||||
|
||||
slug = models.SlugField(
|
||||
max_length=255,
|
||||
verbose_name=_("slug"),
|
||||
)
|
||||
|
||||
uic = models.IntegerField(
|
||||
verbose_name=_("UIC"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
uic8_sncf = models.IntegerField(
|
||||
verbose_name=_("UIC8 SNCF"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
latitude = models.FloatField(
|
||||
verbose_name=_("latitude"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
longitude = models.FloatField(
|
||||
verbose_name=_("longitude"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
parent_station = models.ForeignKey(
|
||||
"Station",
|
||||
on_delete=models.CASCADE,
|
||||
verbose_name=_("parent station"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
related_name="children",
|
||||
)
|
||||
|
||||
country = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("country"),
|
||||
choices=Country,
|
||||
)
|
||||
|
||||
time_zone = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("timezone"),
|
||||
)
|
||||
|
||||
is_city = models.BooleanField(
|
||||
verbose_name=_("is city"),
|
||||
)
|
||||
|
||||
is_main_station = models.BooleanField(
|
||||
verbose_name=_("is main station"),
|
||||
)
|
||||
|
||||
is_airport = models.BooleanField(
|
||||
verbose_name=_("is airport"),
|
||||
)
|
||||
|
||||
is_suggestable = models.BooleanField(
|
||||
verbose_name=_("is suggestable"),
|
||||
)
|
||||
|
||||
country_hint = models.BooleanField(
|
||||
verbose_name=_("country hint"),
|
||||
)
|
||||
|
||||
main_station_hint = models.BooleanField(
|
||||
verbose_name=_("main station hint"),
|
||||
)
|
||||
|
||||
sncf_id = models.CharField(
|
||||
max_length=5,
|
||||
verbose_name=_("SNCF ID"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
sncf_tvs_id = models.CharField(
|
||||
max_length=3,
|
||||
verbose_name=_("SNCF TVS ID"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
sncf_is_enabled = models.BooleanField(
|
||||
verbose_name=_("SNCF is enabled"),
|
||||
)
|
||||
|
||||
entur_id = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("Entur ID"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
entur_is_enabled = models.BooleanField(
|
||||
verbose_name=_("Entur is enabled"),
|
||||
)
|
||||
|
||||
db_id = models.IntegerField(
|
||||
verbose_name=_("DB ID"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
db_is_enabled = models.BooleanField(
|
||||
verbose_name=_("DB is enabled"),
|
||||
)
|
||||
|
||||
busbud_id = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("Busbud ID"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
busbud_is_enabled = models.BooleanField(
|
||||
verbose_name=_("Busbud is enabled"),
|
||||
)
|
||||
|
||||
distribusion_id = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("distribusion ID"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
distribusion_is_enabled = models.BooleanField(
|
||||
verbose_name=_("distribusion is enabled"),
|
||||
)
|
||||
|
||||
flixbus_id = models.IntegerField(
|
||||
verbose_name=_("Flixbus ID"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
flixbus_is_enabled = models.BooleanField(
|
||||
verbose_name=_("Flixbus is enabled"),
|
||||
)
|
||||
|
||||
cff_id = models.IntegerField(
|
||||
verbose_name=_("CFF ID"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
cff_is_enabled = models.BooleanField(
|
||||
verbose_name=_("CFF is enabled"),
|
||||
)
|
||||
|
||||
leoexpress_id = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("Leo Express ID"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
leoexpress_is_enabled = models.BooleanField(
|
||||
verbose_name=_("Leo Express is enabled"),
|
||||
)
|
||||
|
||||
obb_id = models.IntegerField(
|
||||
verbose_name=_("ÖBB ID"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
obb_is_enabled = models.BooleanField(
|
||||
verbose_name=_("ÖBB is enabled"),
|
||||
)
|
||||
|
||||
ouigo_id = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("Ouigo ID"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
ouigo_is_enabled = models.BooleanField(
|
||||
verbose_name=_("Ouigo is enabled"),
|
||||
)
|
||||
|
||||
trenitalia_id = models.IntegerField(
|
||||
verbose_name=_("Trenitalia ID"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
trenitalia_is_enabled = models.BooleanField(
|
||||
verbose_name=_("Trenitalia is enabled"),
|
||||
)
|
||||
|
||||
trenitalia_rtvt_id = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("Trenitalia RTVT ID"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
trenord_id = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("Trenord ID"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
ntv_rtiv_id = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("NTV RTIV ID"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
ntv_id = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("NTV ID"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
ntv_is_enabled = models.BooleanField(
|
||||
verbose_name=_("NTV is enabled"),
|
||||
)
|
||||
|
||||
hkx_id = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("HKX ID"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
hkx_is_enabled = models.BooleanField(
|
||||
verbose_name=_("HKX is enabled"),
|
||||
)
|
||||
|
||||
renfe_id = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("Renfe ID"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
renfe_is_enabled = models.BooleanField(
|
||||
verbose_name=_("Renfe is enabled"),
|
||||
)
|
||||
|
||||
atoc_id = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("ATOC ID"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
atoc_is_enabled = models.BooleanField(
|
||||
verbose_name=_("ATOC is enabled"),
|
||||
)
|
||||
|
||||
benerail_id = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("Benerail ID"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
benerail_is_enabled = models.BooleanField(
|
||||
verbose_name=_("Benerail is enabled"),
|
||||
)
|
||||
|
||||
westbahn_id = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("Westbahn ID"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
westbahn_is_enabled = models.BooleanField(
|
||||
verbose_name=_("Westbahn is enabled"),
|
||||
)
|
||||
|
||||
sncf_self_service_machine = models.BooleanField(
|
||||
verbose_name=_("SNCF self-service machine"),
|
||||
)
|
||||
|
||||
same_as = models.ForeignKey(
|
||||
"Station",
|
||||
on_delete=models.CASCADE,
|
||||
verbose_name=_("same as"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
related_name="same_as_other",
|
||||
)
|
||||
|
||||
info_de = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("info (DE)"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
info_en = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("info (EN)"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
info_es = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("info (ES)"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
info_fr = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("info (FR)"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
info_it = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("info (IT)"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
info_nb = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("info (NB)"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
info_nl = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("info (NL)"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
info_cs = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("info (CS)"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
info_da = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("info (DA)"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
info_hu = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("info (HU)"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
info_ja = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("info (JA)"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
info_ko = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("info (KO)"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
info_pl = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("info (PL)"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
info_pt = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("info (PT)"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
info_ru = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("info (RU)"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
info_sv = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("info (SV)"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
info_tr = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("info (TR)"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
info_zh = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("info (ZH)"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
normalized_code_trainline = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("normalized code (Trainline)"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
iata_airport_code = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("IATA airport code"),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
def get_near_stops(self, radius: float = settings.STATION_RADIUS) -> QuerySet[Stop]:
|
||||
"""
|
||||
Returns a queryset of all stops that are in a radius of radius meters around the station.
|
||||
It calculates a distance from each stop to the station using spatial coordinates.
|
||||
"""
|
||||
return Stop.objects.annotate(distance=6371000 * ACos(
|
||||
Sin(Radians(self.latitude)) * Sin(Radians(F('lat')))
|
||||
+ Cos(Radians(self.latitude)) * Cos(Radians(F('lat'))) * Cos(Radians(F('lon')) - Radians(self.longitude))))\
|
||||
.filter(distance__lte=radius)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("station")
|
||||
verbose_name_plural = _("stations")
|
@ -1,3 +0,0 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
@ -1,3 +0,0 @@
|
||||
from django.shortcuts import render
|
||||
|
||||
# Create your views here.
|
@ -88,15 +88,5 @@
|
||||
"feed_url": "https://opentransportdata.swiss/fr/dataset/timetable-2024-gtfs2020/permalink",
|
||||
"rt_feed_url": "https://api.opentransportdata.swiss/gtfsrt2020"
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "gtfs.gtfsfeed",
|
||||
"pk": "LU-ALL",
|
||||
"fields": {
|
||||
"name": "CFL",
|
||||
"country": "LU",
|
||||
"feed_url": "https://data.public.lu/fr/datasets/r/aab2922d-27ff-4e53-a789-d990cf1ceb1e",
|
||||
"rt_feed_url": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -155,7 +155,7 @@ class Command(BaseCommand):
|
||||
unique_fields=['id'])
|
||||
routes.clear()
|
||||
|
||||
Calendar.objects.filter(gtfs_feed=gtfs_feed).delete()
|
||||
# Calendar.objects.filter(gtfs_feed=gtfs_feed).delete()
|
||||
calendars = {}
|
||||
if "calendar.txt" in zipfile.namelist():
|
||||
for calendar_dict in csv.DictReader(tqdm(read_file("calendar.txt"), desc="Calendars")):
|
||||
@ -294,14 +294,14 @@ class Command(BaseCommand):
|
||||
dep_h, dep_m, dep_s = map(int, dep_time.split(':'))
|
||||
dep_time = dep_h * 3600 + dep_m * 60 + dep_s
|
||||
|
||||
pickup_type = stop_time_dict.get('pickup_type', PickupType.REGULAR)
|
||||
drop_off_type = stop_time_dict.get('drop_off_type', PickupType.REGULAR)
|
||||
# if stop_time_dict['stop_sequence'] == "1":
|
||||
# # First stop
|
||||
# drop_off_type = PickupType.NONE
|
||||
# elif arr_time == dep_time:
|
||||
# # Last stop
|
||||
# pickup_type = PickupType.NONE
|
||||
pickup_type = stop_time_dict.get('pickup_type', 0)
|
||||
drop_off_type = stop_time_dict.get('drop_off_type', 0)
|
||||
if stop_time_dict['stop_sequence'] == "1":
|
||||
# First stop
|
||||
drop_off_type = PickupType.NONE
|
||||
elif arr_time == dep_time:
|
||||
# Last stop
|
||||
pickup_type = PickupType.NONE
|
||||
|
||||
st = StopTime(
|
||||
id=f"{gtfs_code}-{stop_time_dict['trip_id']}-{stop_time_dict['stop_id']}"
|
||||
@ -349,7 +349,7 @@ class Command(BaseCommand):
|
||||
from_stop_id=from_stop_id,
|
||||
to_stop_id=to_stop_id,
|
||||
transfer_type=transfer_dict['transfer_type'],
|
||||
min_transfer_time=transfer_dict.get('min_transfer_time', 0) or 0,
|
||||
min_transfer_time=transfer_dict['min_transfer_time'],
|
||||
)
|
||||
transfers.append(transfer)
|
||||
|
||||
|
@ -30,7 +30,7 @@ class Command(BaseCommand):
|
||||
headers = {}
|
||||
if gtfs_code == "CH-ALL":
|
||||
headers["Authorization"] = settings.OPENTRANSPORTDATA_SWISS_TOKEN
|
||||
resp = requests.get(gtfs_feed.rt_feed_url, allow_redirects=True, headers=headers)
|
||||
resp = requests.get(gtfs_feed.rt_feed_url, allow_redirects=True)
|
||||
feed_message = FeedMessage()
|
||||
feed_message.ParseFromString(resp.content)
|
||||
|
||||
@ -41,88 +41,87 @@ class Command(BaseCommand):
|
||||
f.write(str(feed_message))
|
||||
|
||||
for entity in feed_message.entity:
|
||||
try:
|
||||
if entity.HasField("trip_update"):
|
||||
trip_update = entity.trip_update
|
||||
trip_id = trip_update.trip.trip_id
|
||||
trip_id = f"{gtfs_code}-{trip_id}"
|
||||
if entity.HasField("trip_update"):
|
||||
trip_update = entity.trip_update
|
||||
trip_id = trip_update.trip.trip_id
|
||||
trip_id = f"{gtfs_code}-{trip_id}"
|
||||
|
||||
start_date = date(year=int(trip_update.trip.start_date[:4]),
|
||||
month=int(trip_update.trip.start_date[4:6]),
|
||||
day=int(trip_update.trip.start_date[6:]))
|
||||
start_dt = datetime.combine(start_date, time(0), tzinfo=ZoneInfo("Europe/Paris"))
|
||||
start_date = date(year=int(trip_update.trip.start_date[:4]),
|
||||
month=int(trip_update.trip.start_date[4:6]),
|
||||
day=int(trip_update.trip.start_date[6:]))
|
||||
start_dt = datetime.combine(start_date, time(0), tzinfo=ZoneInfo("Europe/Paris"))
|
||||
|
||||
if trip_update.trip.schedule_relationship == TripScheduleRelationship.ADDED:
|
||||
# C'est un trajet nouveau. On crée le trajet associé.
|
||||
self.create_trip(trip_update, trip_id, start_dt, gtfs_feed)
|
||||
if trip_update.trip.schedule_relationship == TripScheduleRelationship.ADDED:
|
||||
# C'est un trajet nouveau. On crée le trajet associé.
|
||||
self.create_trip(trip_update, trip_id, start_dt, gtfs_feed)
|
||||
|
||||
if not Trip.objects.filter(id=trip_id).exists():
|
||||
self.stdout.write(f"Trip {trip_id} does not exist in the GTFS feed.")
|
||||
continue
|
||||
if not Trip.objects.filter(id=trip_id).exists():
|
||||
self.stdout.write(f"Trip {trip_id} does not exist in the GTFS feed.")
|
||||
continue
|
||||
|
||||
# Création du TripUpdate
|
||||
tu, _created = TripUpdate.objects.update_or_create(
|
||||
trip_id=trip_id,
|
||||
start_date=trip_update.trip.start_date,
|
||||
start_time=trip_update.trip.start_time,
|
||||
defaults=dict(
|
||||
schedule_relationship=trip_update.trip.schedule_relationship,
|
||||
)
|
||||
# Création du TripUpdate
|
||||
tu, _created = TripUpdate.objects.update_or_create(
|
||||
trip_id=trip_id,
|
||||
start_date=trip_update.trip.start_date,
|
||||
start_time=trip_update.trip.start_time,
|
||||
defaults=dict(
|
||||
schedule_relationship=trip_update.trip.schedule_relationship,
|
||||
)
|
||||
)
|
||||
|
||||
for stop_sequence, stop_time_update in enumerate(trip_update.stop_time_update):
|
||||
stop_id = stop_time_update.stop_id
|
||||
stop_id = f"{gtfs_code}-{stop_id}"
|
||||
if StopTime.objects.filter(trip_id=trip_id, stop=stop_id).exists():
|
||||
st = StopTime.objects.filter(trip_id=trip_id, stop=stop_id)
|
||||
if st.count() > 1:
|
||||
st = st.get(stop_sequence=stop_sequence)
|
||||
else:
|
||||
st = st.first()
|
||||
for stop_sequence, stop_time_update in enumerate(trip_update.stop_time_update):
|
||||
stop_id = stop_time_update.stop_id
|
||||
stop_id = f"{gtfs_code}-{stop_id}"
|
||||
if StopTime.objects.filter(trip_id=trip_id, stop=stop_id).exists():
|
||||
st = StopTime.objects.filter(trip_id=trip_id, stop=stop_id)
|
||||
if st.count() > 1:
|
||||
st = st.get(stop_sequence=stop_sequence)
|
||||
else:
|
||||
# Stop is added
|
||||
st = StopTime.objects.create(
|
||||
id=f"{trip_id}-{stop_time_update.stop_id}",
|
||||
trip_id=trip_id,
|
||||
stop_id=stop_id,
|
||||
stop_sequence=stop_sequence,
|
||||
arrival_time=datetime.fromtimestamp(stop_time_update.arrival.time,
|
||||
tz=ZoneInfo("Europe/Paris")) - start_dt,
|
||||
departure_time=datetime.fromtimestamp(stop_time_update.departure.time,
|
||||
tz=ZoneInfo("Europe/Paris")) - start_dt,
|
||||
pickup_type=(PickupType.REGULAR if stop_time_update.departure.time
|
||||
else PickupType.NONE),
|
||||
drop_off_type=(PickupType.REGULAR if stop_time_update.arrival.time
|
||||
else PickupType.NONE),
|
||||
)
|
||||
st = st.first()
|
||||
else:
|
||||
# Stop is added
|
||||
st = StopTime.objects.create(
|
||||
id=f"{trip_id}-{stop_time_update.stop_id}",
|
||||
trip_id=trip_id,
|
||||
stop_id=stop_id,
|
||||
defaults={
|
||||
"stop_sequence": stop_sequence,
|
||||
"arrival_time": datetime.fromtimestamp(stop_time_update.arrival.time,
|
||||
tz=ZoneInfo("Europe/Paris")) - start_dt,
|
||||
"departure_time": datetime.fromtimestamp(stop_time_update.departure.time,
|
||||
tz=ZoneInfo("Europe/Paris")) - start_dt,
|
||||
"pickup_type": (PickupType.REGULAR if stop_time_update.departure.time
|
||||
else PickupType.NONE),
|
||||
"drop_off_type": (PickupType.REGULAR if stop_time_update.arrival.time
|
||||
else PickupType.NONE),
|
||||
}
|
||||
)
|
||||
|
||||
if stop_time_update.schedule_relationship == StopScheduleRelationship.SKIPPED:
|
||||
if st.pickup_type != PickupType.NONE or st.drop_off_type != PickupType.NONE:
|
||||
st.pickup_type = PickupType.NONE
|
||||
st.drop_off_type = PickupType.NONE
|
||||
st.save()
|
||||
|
||||
if st.stop_sequence != stop_sequence:
|
||||
st.stop_sequence = stop_sequence
|
||||
if stop_time_update.schedule_relationship == StopScheduleRelationship.SKIPPED:
|
||||
if st.pickup_type != PickupType.NONE or st.drop_off_type != PickupType.NONE:
|
||||
st.pickup_type = PickupType.NONE
|
||||
st.drop_off_type = PickupType.NONE
|
||||
st.save()
|
||||
|
||||
st_update = StopTimeUpdate(
|
||||
trip_update=tu,
|
||||
stop_time=st,
|
||||
arrival_delay=timedelta(seconds=stop_time_update.arrival.delay),
|
||||
arrival_time=datetime.fromtimestamp(stop_time_update.arrival.time,
|
||||
tz=ZoneInfo("Europe/Paris")),
|
||||
departure_delay=timedelta(seconds=stop_time_update.departure.delay),
|
||||
departure_time=datetime.fromtimestamp(stop_time_update.departure.time,
|
||||
tz=ZoneInfo("Europe/Paris")),
|
||||
schedule_relationship=stop_time_update.schedule_relationship
|
||||
or StopScheduleRelationship.SCHEDULED,
|
||||
)
|
||||
stop_times_updates.append(st_update)
|
||||
else:
|
||||
self.stdout.write(str(entity))
|
||||
except Exception as e:
|
||||
self.stderr.write(self.style.ERROR(f"Error while processing entity: {e}"))
|
||||
if st.stop_sequence != stop_sequence:
|
||||
st.stop_sequence = stop_sequence
|
||||
st.save()
|
||||
|
||||
st_update = StopTimeUpdate(
|
||||
trip_update=tu,
|
||||
stop_time=st,
|
||||
arrival_delay=timedelta(seconds=stop_time_update.arrival.delay),
|
||||
arrival_time=datetime.fromtimestamp(stop_time_update.arrival.time,
|
||||
tz=ZoneInfo("Europe/Paris")),
|
||||
departure_delay=timedelta(seconds=stop_time_update.departure.delay),
|
||||
departure_time=datetime.fromtimestamp(stop_time_update.departure.time,
|
||||
tz=ZoneInfo("Europe/Paris")),
|
||||
schedule_relationship=stop_time_update.schedule_relationship
|
||||
or StopScheduleRelationship.SCHEDULED,
|
||||
)
|
||||
stop_times_updates.append(st_update)
|
||||
else:
|
||||
self.stdout.write(str(entity))
|
||||
|
||||
StopTimeUpdate.objects.bulk_create(stop_times_updates,
|
||||
update_conflicts=True,
|
||||
|
@ -45,7 +45,6 @@ INSTALLED_APPS = [
|
||||
"rest_framework",
|
||||
|
||||
"trainvel.api",
|
||||
"trainvel.core",
|
||||
"trainvel.gtfs",
|
||||
]
|
||||
|
||||
@ -151,8 +150,6 @@ REST_FRAMEWORK = {
|
||||
'PAGE_SIZE': 20,
|
||||
}
|
||||
|
||||
STATION_RADIUS = 300
|
||||
|
||||
OPENTRANSPORTDATA_SWISS_TOKEN = "CHANGE ME"
|
||||
|
||||
|
||||
|
@ -18,12 +18,11 @@ from django.contrib import admin
|
||||
from django.urls import path, include
|
||||
from rest_framework import routers
|
||||
|
||||
from trainvel.api.views import AgencyViewSet, StopViewSet, RouteViewSet, StationViewSet, TripViewSet, StopTimeViewSet, \
|
||||
from trainvel.api.views import AgencyViewSet, StopViewSet, RouteViewSet, TripViewSet, StopTimeViewSet, \
|
||||
CalendarViewSet, CalendarDateViewSet, TransferViewSet, FeedInfoViewSet, NextDeparturesViewSet, NextArrivalsViewSet, \
|
||||
TripUpdateViewSet, StopTimeUpdateViewSet
|
||||
|
||||
router = routers.DefaultRouter()
|
||||
router.register("core/station", StationViewSet)
|
||||
router.register("gtfs/agency", AgencyViewSet)
|
||||
router.register("gtfs/stop", StopViewSet)
|
||||
router.register("gtfs/route", RouteViewSet)
|
||||
|
Loading…
x
Reference in New Issue
Block a user