trainvel/sncfgtfs/models.py

902 lines
22 KiB
Python
Raw Normal View History

2024-01-26 00:31:14 +00:00
from django.db import models
from django.utils.translation import gettext_lazy as _
class Country(models.TextChoices):
"""
Country list by ISO 3166-1 alpha-2 code.
Only countries that are member of the Council of Europe
are listed for now.
"""
ALBANIA = "AL", _("Albania")
ANDORRA = "AD", _("Andorra")
ARMENIA = "AM", _("Armenia")
AUSTRIA = "AT", _("Austria")
AZERBAIJAN = "AZ", _("Azerbaijan")
BELGIUM = "BE", _("Belgium")
BOSNIA_AND_HERZEGOVINA = "BA", _("Bosnia and Herzegovina")
BULGARIA = "BG", _("Bulgaria")
CROATIA = "HR", _("Croatia")
CYPRUS = "CY", _("Cyprus")
CZECH_REPUBLIC = "CZ", _("Czech Republic")
DENMARK = "DK", _("Denmark")
ESTONIA = "EE", _("Estonia")
FINLAND = "FI", _("Finland")
FRANCE = "FR", _("France")
GEORGIA = "GE", _("Georgia")
GERMANY = "DE", _("Germany")
GREECE = "GR", _("Greece")
HUNGARY = "HU", _("Hungary")
ICELAND = "IS", _("Iceland")
IRELAND = "IE", _("Ireland")
ITALY = "IT", _("Italy")
LATVIA = "LV", _("Latvia")
LIECHTENSTEIN = "LI", _("Liechtenstein")
LITHUANIA = "LT", _("Lithuania")
LUXEMBOURG = "LU", _("Luxembourg")
MALTA = "MT", _("Malta")
MOLDOVA = "MD", _("Moldova")
MONACO = "MC", _("Monaco")
MONTENEGRO = "ME", _("Montenegro")
NETHERLANDS = "NL", _("Netherlands")
NORTH_MACEDONIA = "MK", _("North Macedonia")
NORWAY = "NO", _("Norway")
POLAND = "PL", _("Poland")
PORTUGAL = "PT", _("Portugal")
ROMANIA = "RO", _("Romania")
SAN_MARINO = "SM", _("San Marino")
SERBIA = "RS", _("Serbia")
SLOVAKIA = "SK", _("Slovakia")
SLOVENIA = "SI", _("Slovenia")
SPAIN = "ES", _("Spain")
SWEDEN = "SE", _("Sweden")
SWITZERLAND = "CH", _("Switzerland")
TURKEY = "TR", _("Turkey")
UNITED_KINGDOM = "GB", _("United Kingdom")
UKRAINE = "UA", _("Ukraine")
2024-01-27 09:43:59 +00:00
2024-01-26 00:31:14 +00:00
class LocationType(models.IntegerChoices):
STOP_PLATFORM = 0, _("Stop/platform")
STATION = 1, _("Station")
ENTRANCE_EXIT = 2, _("Entrance/exit")
GENERIC_NODE = 3, _("Generic node")
BOARDING_AREA = 4, _("Boarding area")
class AccessInformation(models.IntegerChoices):
NO_INFORMATION = 0, _("No information")
POSSIBLE = 1, _("Possible")
NOT_POSSIBLE = 2, _("Not possible")
class PickupType(models.IntegerChoices):
REGULAR = 0, _("Regular")
NONE = 1, _("None")
MUST_PHONE_AGENCY = 2, _("Must phone agency")
MUST_COORDINATE_WITH_DRIVER = 3, _("Must coordinate with driver")
class RouteType(models.IntegerChoices):
TRAM = 0, _("Tram")
METRO = 1, _("Metro")
RAIL = 2, _("Rail")
BUS = 3, _("Bus")
FERRY = 4, _("Ferry")
CABLE_CAR = 5, _("Cable car")
GONDOLA = 6, _("Gondola")
FUNICULAR = 7, _("Funicular")
class Direction(models.IntegerChoices):
OUTBOUND = 0, _("Outbound")
INBOUND = 1, _("Inbound")
2024-01-26 20:16:26 +00:00
class TransferType(models.IntegerChoices):
RECOMMENDED = 0, _("Recommended")
TIMED = 1, _("Timed")
MINIMUM_TIME = 2, _("Minimum time")
NOT_POSSIBLE = 3, _("Not possible")
2024-01-27 09:43:59 +00:00
class ExceptionType(models.IntegerChoices):
ADDED = 1, _("Added")
REMOVED = 2, _("Removed")
2024-02-06 07:01:56 +00:00
class TripScheduleRelationship(models.IntegerChoices):
SCHEDULED = 0, _("Scheduled")
ADDED = 1, _("Added")
UNSCHEDULED = 2, _("Unscheduled")
CANCELED = 3, _("Canceled")
REPLACEMENT = 5, _("Replacement")
DUPLICATED = 6, _("Duplicated")
DELETED = 7, _("Deleted")
class StopScheduleRelationship(models.IntegerChoices):
2024-02-04 21:20:09 +00:00
SCHEDULED = 0, _("Scheduled")
SKIPPED = 1, _("Skipped")
NO_DATA = 2, _("No data")
UNSCHEDULED = 3, _("Unscheduled")
class GTFSFeed(models.Model):
code = models.CharField(
primary_key=True,
max_length=64,
verbose_name=_("code"),
help_text=_("Unique code of the feed.")
)
name = models.CharField(
max_length=255,
verbose_name=_("name"),
unique=True,
help_text=_("Full name that describes the feed."),
)
country = models.CharField(
max_length=2,
verbose_name=_("country"),
choices=Country,
)
feed_url = models.URLField(
verbose_name=_("feed URL"),
help_text=_("URL to download the GTFS feed. Must point to a ZIP archive. "
"See https://gtfs.org/schedule/ for more information."),
)
rt_feed_url = models.URLField(
verbose_name=_("realtime feed URL"),
blank=True,
default="",
help_text=_("URL to download the GTFS-Realtime feed, in the GTFS-RT format. "
"See https://gtfs.org/realtime/ for more information."),
)
last_modified = models.DateTimeField(
verbose_name=_("last modified date"),
null=True,
default=None,
)
etag = models.CharField(
max_length=255,
verbose_name=_("ETag"),
blank=True,
default="",
help_text=_("If applicable, corresponds to the tag of the last downloaded file. "
"If it is not modified, the file is the same."),
)
def __str__(self):
return f"{self.name} ({self.code})"
class Meta:
verbose_name = _("GTFS feed")
verbose_name_plural = _("GTFS feeds")
ordering = ('country', 'name',)
indexes = (models.Index(fields=['name']),)
2024-01-26 00:31:14 +00:00
class Agency(models.Model):
2024-01-27 09:43:59 +00:00
id = models.CharField(
2024-01-26 00:31:14 +00:00
max_length=255,
primary_key=True,
verbose_name=_("Agency ID"),
)
2024-01-27 09:43:59 +00:00
name = models.CharField(
2024-01-26 00:31:14 +00:00
max_length=255,
verbose_name=_("Agency name"),
)
2024-01-27 09:43:59 +00:00
url = models.URLField(
2024-01-26 00:31:14 +00:00
verbose_name=_("Agency URL"),
)
2024-01-27 09:43:59 +00:00
timezone = models.CharField(
2024-01-26 00:31:14 +00:00
max_length=255,
verbose_name=_("Agency timezone"),
)
2024-01-27 09:43:59 +00:00
lang = models.CharField(
2024-01-26 00:31:14 +00:00
max_length=255,
verbose_name=_("Agency language"),
blank=True,
)
2024-01-27 09:43:59 +00:00
phone = models.CharField(
max_length=255,
verbose_name=_("Agency phone"),
blank=True,
)
email = models.EmailField(
verbose_name=_("Agency email"),
blank=True,
)
gtfs_feed = models.ForeignKey(
GTFSFeed,
on_delete=models.CASCADE,
verbose_name=_("GTFS feed"),
)
2024-01-27 09:43:59 +00:00
def __str__(self):
return self.name
2024-01-26 00:31:14 +00:00
class Meta:
verbose_name = _("Agency")
verbose_name_plural = _("Agencies")
2024-01-27 14:18:33 +00:00
ordering = ("name",)
indexes = (models.Index(fields=['name']), models.Index(fields=['gtfs_feed']),)
2024-01-26 00:31:14 +00:00
class Stop(models.Model):
2024-01-27 09:43:59 +00:00
id = models.CharField(
2024-01-26 00:31:14 +00:00
max_length=255,
primary_key=True,
verbose_name=_("Stop ID"),
)
2024-01-27 09:43:59 +00:00
code = models.CharField(
2024-01-26 00:31:14 +00:00
max_length=255,
verbose_name=_("Stop code"),
blank=True,
)
2024-01-27 09:43:59 +00:00
name = models.CharField(
2024-01-26 00:31:14 +00:00
max_length=255,
verbose_name=_("Stop name"),
)
2024-01-27 09:43:59 +00:00
desc = models.CharField(
2024-01-26 00:31:14 +00:00
max_length=255,
verbose_name=_("Stop description"),
blank=True,
)
2024-01-27 09:43:59 +00:00
lon = models.FloatField(
2024-01-26 00:31:14 +00:00
verbose_name=_("Stop longitude"),
)
2024-01-27 09:43:59 +00:00
lat = models.FloatField(
2024-01-26 00:31:14 +00:00
verbose_name=_("Stop latitude"),
)
zone_id = models.CharField(
max_length=255,
verbose_name=_("Zone ID"),
blank=True,
2024-01-26 00:31:14 +00:00
)
2024-01-27 09:43:59 +00:00
url = models.URLField(
2024-01-26 00:31:14 +00:00
verbose_name=_("Stop URL"),
blank=True,
)
location_type = models.IntegerField(
verbose_name=_("Location type"),
blank=True,
choices=LocationType,
default=LocationType.STOP_PLATFORM,
)
parent_station = models.ForeignKey(
to="Stop",
on_delete=models.PROTECT,
verbose_name=_("Parent station"),
2024-01-27 09:43:59 +00:00
related_name="children",
2024-01-26 00:31:14 +00:00
blank=True,
2024-01-27 09:43:59 +00:00
null=True,
2024-01-26 00:31:14 +00:00
)
2024-01-27 09:43:59 +00:00
timezone = models.CharField(
2024-01-26 00:31:14 +00:00
max_length=255,
verbose_name=_("Stop timezone"),
blank=True,
)
level_id = models.CharField(
max_length=255,
verbose_name=_("Level ID"),
blank=True,
)
wheelchair_boarding = models.IntegerField(
verbose_name=_("Wheelchair boarding"),
blank=True,
choices=AccessInformation,
default=AccessInformation.NO_INFORMATION,
)
platform_code = models.CharField(
max_length=255,
verbose_name=_("Platform code"),
2024-01-27 09:43:59 +00:00
blank=True,
2024-01-26 00:31:14 +00:00
)
gtfs_feed = models.ForeignKey(
GTFSFeed,
on_delete=models.CASCADE,
verbose_name=_("GTFS feed"),
)
2024-02-04 21:20:09 +00:00
@property
def stop_type(self):
2024-05-08 08:30:25 +00:00
train_type = self.id.split('StopPoint:OCE')[-1].split('StopArea:OCE')[-1].split('-')[0]
2024-02-04 21:20:09 +00:00
return train_type
2024-01-27 09:43:59 +00:00
def __str__(self):
return f"{self.name} ({self.id})"
2024-01-26 00:31:14 +00:00
class Meta:
verbose_name = _("Stop")
verbose_name_plural = _("Stops")
2024-01-27 14:18:33 +00:00
ordering = ("id",)
indexes = (models.Index(fields=['name']),
models.Index(fields=['code']),
models.Index(fields=['gtfs_feed']),)
2024-01-26 00:31:14 +00:00
class Route(models.Model):
2024-01-27 09:43:59 +00:00
id = models.CharField(
2024-01-26 00:31:14 +00:00
max_length=255,
primary_key=True,
2024-01-27 09:43:59 +00:00
verbose_name=_("ID"),
2024-01-26 00:31:14 +00:00
)
agency = models.ForeignKey(
to="Agency",
on_delete=models.CASCADE,
2024-02-09 22:15:14 +00:00
verbose_name=_("Agency"),
2024-01-27 09:43:59 +00:00
related_name="routes",
null=True,
blank=True,
default=None,
2024-01-26 00:31:14 +00:00
)
2024-01-27 09:43:59 +00:00
short_name = models.CharField(
2024-01-26 00:31:14 +00:00
max_length=255,
verbose_name=_("Route short name"),
)
2024-01-27 09:43:59 +00:00
long_name = models.CharField(
2024-01-26 00:31:14 +00:00
max_length=255,
verbose_name=_("Route long name"),
blank=True,
2024-01-26 00:31:14 +00:00
)
2024-01-27 09:43:59 +00:00
desc = models.CharField(
2024-01-26 00:31:14 +00:00
max_length=255,
verbose_name=_("Route description"),
blank=True,
)
2024-01-27 09:43:59 +00:00
type = models.IntegerField(
2024-01-26 00:31:14 +00:00
verbose_name=_("Route type"),
choices=RouteType,
)
2024-01-27 09:43:59 +00:00
url = models.URLField(
2024-01-26 00:31:14 +00:00
verbose_name=_("Route URL"),
blank=True,
)
2024-01-27 09:43:59 +00:00
color = models.CharField(
2024-01-26 00:31:14 +00:00
max_length=255,
verbose_name=_("Route color"),
blank=True,
)
2024-01-27 09:43:59 +00:00
text_color = models.CharField(
2024-01-26 00:31:14 +00:00
max_length=255,
verbose_name=_("Route text color"),
blank=True,
)
gtfs_feed = models.ForeignKey(
GTFSFeed,
on_delete=models.CASCADE,
verbose_name=_("GTFS feed"),
2024-02-09 22:15:14 +00:00
)
2024-01-27 09:43:59 +00:00
def __str__(self):
return self.long_name or self.short_name
2024-01-27 09:43:59 +00:00
2024-01-26 00:31:14 +00:00
class Meta:
verbose_name = _("Route")
verbose_name_plural = _("Routes")
2024-01-27 14:18:33 +00:00
ordering = ("id",)
indexes = (models.Index(fields=['gtfs_feed']),)
2024-01-26 00:31:14 +00:00
class Trip(models.Model):
2024-01-27 09:43:59 +00:00
id = models.CharField(
2024-01-26 00:31:14 +00:00
max_length=255,
primary_key=True,
verbose_name=_("Trip ID"),
)
route = models.ForeignKey(
to="Route",
on_delete=models.CASCADE,
2024-01-27 09:43:59 +00:00
verbose_name=_("Route"),
related_name="trips",
2024-01-26 00:31:14 +00:00
)
2024-01-27 09:43:59 +00:00
service = models.ForeignKey(
to="Calendar",
on_delete=models.CASCADE,
verbose_name=_("Service"),
related_name="trips",
2024-01-26 00:31:14 +00:00
)
2024-01-27 09:43:59 +00:00
headsign = models.CharField(
2024-01-26 00:31:14 +00:00
max_length=255,
verbose_name=_("Trip headsign"),
blank=True,
)
2024-01-27 09:43:59 +00:00
short_name = models.CharField(
2024-01-26 00:31:14 +00:00
max_length=255,
verbose_name=_("Trip short name"),
blank=True,
)
direction_id = models.IntegerField(
verbose_name=_("Direction"),
choices=Direction,
2024-01-27 09:43:59 +00:00
null=True,
2024-01-26 00:31:14 +00:00
)
block_id = models.CharField(
max_length=255,
verbose_name=_("Block ID"),
blank=True,
)
shape_id = models.CharField(
max_length=255,
verbose_name=_("Shape ID"),
blank=True,
)
wheelchair_accessible = models.IntegerField(
verbose_name=_("Wheelchair accessible"),
choices=AccessInformation,
default=AccessInformation.NO_INFORMATION,
2024-01-27 09:43:59 +00:00
null=True,
2024-01-26 00:31:14 +00:00
)
bikes_allowed = models.IntegerField(
verbose_name=_("Bikes allowed"),
choices=AccessInformation,
default=AccessInformation.NO_INFORMATION,
2024-01-27 09:43:59 +00:00
null=True,
2024-01-26 00:31:14 +00:00
)
gtfs_feed = models.ForeignKey(
GTFSFeed,
on_delete=models.CASCADE,
verbose_name=_("GTFS feed"),
2024-02-09 22:15:14 +00:00
)
2024-01-27 12:41:34 +00:00
@property
def origin(self) -> Stop | None:
return self.stop_times.order_by('stop_sequence').first().stop if self.stop_times.exists() else None
2024-01-27 12:41:34 +00:00
2024-01-27 09:43:59 +00:00
@property
def destination(self) -> Stop | None:
return self.stop_times.order_by('-stop_sequence').first().stop if self.stop_times.exists() else None
2024-01-27 12:41:34 +00:00
2024-02-09 22:15:14 +00:00
@property
def departure_time(self):
if not self.stop_times.exists():
return _("Unknown")
2024-02-09 22:15:14 +00:00
dep_time = self.stop_times.order_by('stop_sequence').first().departure_time
hours = int(dep_time.total_seconds() // 3600)
minutes = int((dep_time.total_seconds() % 3600) // 60)
return f"{hours:02}:{minutes:02}"
@property
def arrival_time(self):
if not self.stop_times.exists():
return _("Unknown")
2024-02-09 22:15:14 +00:00
arr_time = self.stop_times.order_by('-stop_sequence').first().arrival_time
hours = int(arr_time.total_seconds() // 3600)
minutes = int((arr_time.total_seconds() % 3600) // 60)
return f"{hours:02}:{minutes:02}"
2024-01-27 12:41:34 +00:00
@property
def train_type(self):
if self.gtfs_feed.code == "FR-IDF-TN":
2024-01-27 12:41:34 +00:00
return self.route.short_name
else:
2024-02-04 21:20:09 +00:00
return self.origin.stop_type
2024-01-27 12:41:34 +00:00
@property
def train_number(self):
if self.gtfs_feed.code == "FR-IDF-TN":
2024-01-27 12:41:34 +00:00
return self.short_name
else:
return self.headsign
@property
def color(self):
if self.route.color:
return self.route.color
elif self.train_type == "OUIGO":
return "E60075"
return "FFFFFF"
@property
def text_color(self):
if self.route.text_color:
return self.route.text_color
elif self.train_type == "OUIGO":
return "FFFFFF"
elif self.train_type == "TGV INOUI":
return "9B2743"
elif self.train_type == "INTER-CITÉS" or self.train_type == "INTER-CITÉS de nuit":
return "404042"
return "000000"
2024-01-27 09:43:59 +00:00
@property
def origin_destination(self):
origin = self.origin
origin = origin.name if origin else _("Unknown")
destination = self.destination
destination = destination.name if destination else _("Unknown")
return f"{origin} {self.departure_time}{destination} {self.arrival_time}"
origin_destination.fget.short_description = _("Origin → Destination")
2024-01-27 09:43:59 +00:00
def __str__(self):
return self.origin_destination
2024-01-27 09:43:59 +00:00
2024-01-26 00:31:14 +00:00
class Meta:
verbose_name = _("Trip")
verbose_name_plural = _("Trips")
indexes = (models.Index(fields=['route']), models.Index(fields=['gtfs_feed']),)
2024-01-26 00:31:14 +00:00
class StopTime(models.Model):
2024-01-27 09:43:59 +00:00
id = models.CharField(
max_length=255,
primary_key=True,
verbose_name=_("ID"),
)
trip = models.ForeignKey(
2024-01-26 00:31:14 +00:00
to="Trip",
on_delete=models.CASCADE,
2024-01-27 09:43:59 +00:00
verbose_name=_("Trip"),
related_name="stop_times",
2024-01-26 00:31:14 +00:00
)
2024-01-27 10:43:01 +00:00
arrival_time = models.DurationField(
2024-01-26 00:31:14 +00:00
verbose_name=_("Arrival time"),
)
2024-01-27 10:43:01 +00:00
departure_time = models.DurationField(
2024-01-26 00:31:14 +00:00
verbose_name=_("Departure time"),
)
stop = models.ForeignKey(
to="Stop",
on_delete=models.CASCADE,
verbose_name=_("Stop ID"),
2024-01-27 09:43:59 +00:00
related_name="stop_times",
2024-01-26 00:31:14 +00:00
)
stop_sequence = models.IntegerField(
verbose_name=_("Stop sequence"),
)
stop_headsign = models.CharField(
max_length=255,
verbose_name=_("Stop headsign"),
blank=True,
)
pickup_type = models.IntegerField(
verbose_name=_("Pickup type"),
choices=PickupType,
default=PickupType.REGULAR,
2024-01-27 09:43:59 +00:00
null=True,
2024-01-26 00:31:14 +00:00
)
drop_off_type = models.IntegerField(
verbose_name=_("Drop off type"),
choices=PickupType,
default=PickupType.REGULAR,
2024-01-27 09:43:59 +00:00
null=True,
2024-01-26 00:31:14 +00:00
)
timepoint = models.BooleanField(
verbose_name=_("Timepoint"),
default=True,
2024-01-27 09:43:59 +00:00
null=True,
2024-01-26 00:31:14 +00:00
)
2024-01-27 10:43:01 +00:00
@property
def pretty_arrival_time(self):
seconds = self.arrival_time.total_seconds()
hours = int(seconds // 3600) % 24
minutes = int((seconds % 3600) // 60)
return f"{hours:02}:{minutes:02}"
@property
def pretty_departure_time(self):
seconds = self.departure_time.total_seconds()
hours = int(seconds // 3600) % 24
minutes = int((seconds % 3600) // 60)
return f"{hours:02}:{minutes:02}"
2024-01-27 09:43:59 +00:00
def __str__(self):
2024-02-09 22:15:14 +00:00
return f"{self.stop.name} - {self.trip_id}"
2024-01-27 09:43:59 +00:00
2024-01-26 00:31:14 +00:00
class Meta:
verbose_name = _("Stop time")
verbose_name_plural = _("Stop times")
indexes = (models.Index(fields=['stop']), models.Index(fields=['trip']),)
2024-01-26 00:31:14 +00:00
class Calendar(models.Model):
2024-01-27 09:43:59 +00:00
id = models.CharField(
2024-01-26 00:31:14 +00:00
max_length=255,
primary_key=True,
verbose_name=_("Service ID"),
)
monday = models.BooleanField(
verbose_name=_("Monday"),
)
tuesday = models.BooleanField(
verbose_name=_("Tuesday"),
)
wednesday = models.BooleanField(
verbose_name=_("Wednesday"),
)
thursday = models.BooleanField(
verbose_name=_("Thursday"),
)
friday = models.BooleanField(
verbose_name=_("Friday"),
)
saturday = models.BooleanField(
verbose_name=_("Saturday"),
)
sunday = models.BooleanField(
verbose_name=_("Sunday"),
)
start_date = models.DateField(
verbose_name=_("Start date"),
)
end_date = models.DateField(
verbose_name=_("End date"),
)
gtfs_feed = models.ForeignKey(
GTFSFeed,
on_delete=models.CASCADE,
verbose_name=_("GTFS feed"),
2024-01-27 09:43:59 +00:00
)
def __str__(self):
return self.id
2024-01-26 00:31:14 +00:00
class Meta:
verbose_name = _("Calendar")
verbose_name_plural = _("Calendars")
2024-01-27 14:18:33 +00:00
ordering = ("id",)
indexes = (models.Index(fields=['gtfs_feed']),)
2024-01-26 00:31:14 +00:00
class CalendarDate(models.Model):
2024-01-27 09:43:59 +00:00
id = models.CharField(
max_length=255,
primary_key=True,
verbose_name=_("ID"),
)
service = models.ForeignKey(
2024-01-26 00:31:14 +00:00
to="Calendar",
on_delete=models.CASCADE,
2024-01-27 09:43:59 +00:00
verbose_name=_("Service"),
related_name="dates",
2024-01-26 00:31:14 +00:00
)
date = models.DateField(
verbose_name=_("Date"),
)
exception_type = models.IntegerField(
verbose_name=_("Exception type"),
2024-01-27 09:43:59 +00:00
choices=ExceptionType,
2024-01-26 00:31:14 +00:00
)
2024-01-27 09:43:59 +00:00
def __str__(self):
return f"{self.service.id} - {self.date} - {self.exception_type}"
2024-01-26 00:31:14 +00:00
class Meta:
verbose_name = _("Calendar date")
verbose_name_plural = _("Calendar dates")
2024-01-27 14:18:33 +00:00
ordering = ("id",)
indexes = (models.Index(fields=['service']), models.Index(fields=['date']),)
2024-01-26 00:31:14 +00:00
class Transfer(models.Model):
2024-01-27 09:43:59 +00:00
id = models.CharField(
max_length=255,
primary_key=True,
verbose_name=_("ID"),
)
2024-01-26 00:31:14 +00:00
from_stop = models.ForeignKey(
to="Stop",
on_delete=models.CASCADE,
verbose_name=_("From stop"),
related_name="transfers_from",
)
to_stop = models.ForeignKey(
to="Stop",
on_delete=models.CASCADE,
verbose_name=_("To stop"),
related_name="transfers_to",
)
transfer_type = models.IntegerField(
verbose_name=_("Transfer type"),
2024-01-26 20:16:26 +00:00
choices=TransferType,
default=TransferType.RECOMMENDED,
2024-01-26 00:31:14 +00:00
)
min_transfer_time = models.IntegerField(
verbose_name=_("Minimum transfer time"),
blank=True,
)
class Meta:
verbose_name = _("Transfer")
verbose_name_plural = _("Transfers")
2024-01-27 14:18:33 +00:00
ordering = ("id",)
2024-01-26 00:31:14 +00:00
class FeedInfo(models.Model):
2024-01-27 14:18:33 +00:00
publisher_name = models.CharField(
2024-01-26 00:31:14 +00:00
max_length=255,
verbose_name=_("Feed publisher name"),
)
2024-01-27 14:18:33 +00:00
publisher_url = models.URLField(
2024-01-26 00:31:14 +00:00
verbose_name=_("Feed publisher URL"),
)
2024-01-27 14:18:33 +00:00
lang = models.CharField(
2024-01-26 00:31:14 +00:00
max_length=255,
verbose_name=_("Feed language"),
)
2024-01-27 14:18:33 +00:00
start_date = models.DateField(
2024-01-26 00:31:14 +00:00
verbose_name=_("Feed start date"),
)
2024-01-27 14:18:33 +00:00
end_date = models.DateField(
2024-01-26 00:31:14 +00:00
verbose_name=_("Feed end date"),
)
2024-01-27 14:18:33 +00:00
version = models.CharField(
2024-01-26 00:31:14 +00:00
max_length=255,
verbose_name=_("Feed version"),
)
gtfs_feed = models.ForeignKey(
GTFSFeed,
on_delete=models.CASCADE,
verbose_name=_("GTFS feed"),
)
2024-01-26 00:31:14 +00:00
class Meta:
verbose_name = _("Feed info")
verbose_name_plural = _("Feed infos")
2024-01-27 14:18:33 +00:00
ordering = ("publisher_name",)
indexes = (models.Index(fields=['gtfs_feed']),)
2024-02-04 21:20:09 +00:00
class TripUpdate(models.Model):
trip = models.OneToOneField(
to="Trip",
on_delete=models.CASCADE,
verbose_name=_("Trip"),
related_name="update",
primary_key=True,
)
start_date = models.DateField(
verbose_name=_("Start date"),
)
start_time = models.TimeField(
verbose_name=_("Start time"),
)
schedule_relationship = models.IntegerField(
verbose_name=_("Schedule relationship"),
2024-02-06 07:01:56 +00:00
choices=TripScheduleRelationship,
default=TripScheduleRelationship.SCHEDULED,
2024-02-04 21:20:09 +00:00
)
def __str__(self):
return str(self.trip)
class Meta:
verbose_name = _("Trip update")
verbose_name_plural = _("Trip updates")
ordering = ("start_date", "trip",)
unique_together = ("trip", "start_date", "start_time",)
indexes = (models.Index(fields=['trip']),)
2024-02-04 21:20:09 +00:00
class StopTimeUpdate(models.Model):
trip_update = models.ForeignKey(
to="TripUpdate",
on_delete=models.CASCADE,
verbose_name=_("Trip update"),
related_name="stop_time_updates",
)
stop_time = models.OneToOneField(
to="StopTime",
on_delete=models.CASCADE,
verbose_name=_("Stop time"),
related_name="update",
primary_key=True,
)
arrival_delay = models.DurationField(
verbose_name=_("Arrival delay"),
)
arrival_time = models.DateTimeField(
verbose_name=_("Arrival time"),
)
departure_delay = models.DurationField(
verbose_name=_("Departure delay"),
)
departure_time = models.DateTimeField(
verbose_name=_("Departure time"),
)
schedule_relationship = models.IntegerField(
verbose_name=_("Schedule relationship"),
2024-02-06 07:01:56 +00:00
choices=StopScheduleRelationship,
default=StopScheduleRelationship.SCHEDULED,
2024-02-04 21:20:09 +00:00
)
def __str__(self):
return str(self.trip_update)
class Meta:
verbose_name = _("Stop time update")
verbose_name_plural = _("Stop time updates")
ordering = ("trip_update", "stop_time",)
unique_together = ("trip_update", "stop_time",)
indexes = (models.Index(fields=['trip_update']), models.Index(fields=['stop_time']),)