class FeedInfo(Base): """Information about the feed""" feed = models.ForeignKey('Feed') publisher_name = models.CharField( max_length=255, help_text="Full name of organization that publishes the feed.") publisher_url = models.URLField( help_text="URL of the feed publisher's organization.") lang = models.CharField( max_length=20, help_text="IETF BCP 47 language code for text in field.") start_date = models.DateField( null=True, blank=True, help_text="Date that feed starts providing reliable data.") end_date = models.DateField( null=True, blank=True, help_text="Date that feed stops providing reliable data.") version = models.CharField(max_length=255, blank=True, help_text="Version of feed.") def __unicode__(self): return u'%s-%s' % (self.feed.id, self.publisher_name) class Meta: db_table = 'multigtfs_feedinfo' app_label = 'multigtfs' verbose_name_plural = "feed info" _column_map = (('feed_publisher_name', 'publisher_name'), ('feed_publisher_url', 'publisher_url'), ('feed_lang', 'lang'), ('feed_start_date', 'start_date'), ('feed_end_date', 'end_date'), ('feed_version', 'version'))
class StopTime(Base): """A specific stop on a route on a trip. This implements stop_times.txt in the GTFS feed """ trip = models.ForeignKey(Trip, on_delete=models.CASCADE) stop = models.ForeignKey(Stop, on_delete=models.CASCADE) arrival_time = SecondsField( default=None, null=True, blank=True, help_text="Arrival time. Must be set for end stops of trip.") departure_time = SecondsField( default=None, null=True, blank=True, help_text='Departure time. Must be set for end stops of trip.') stop_sequence = models.IntegerField() stop_headsign = models.CharField( max_length=255, blank=True, help_text="Sign text that identifies the stop for passengers") pickup_type = models.CharField( max_length=1, blank=True, choices=(('0', 'Regularly scheduled pickup'), ('1', 'No pickup available'), ('2', 'Must phone agency to arrange pickup'), ('3', 'Must coordinate with driver to arrange pickup')), help_text="How passengers are picked up") drop_off_type = models.CharField( max_length=1, blank=True, choices=(('0', 'Regularly scheduled drop off'), ('1', 'No drop off available'), ('2', 'Must phone agency to arrange drop off'), ('3', 'Must coordinate with driver to arrange drop off')), help_text="How passengers are picked up") shape_dist_traveled = models.FloatField( "shape distance traveled", null=True, blank=True, help_text='Distance of stop from start of shape') extra_data = JSONField(default={}, blank=True, null=True) def __str__(self): return "%s-%s-%s" % (self.trip, self.stop.stop_id, self.stop_sequence) class Meta: db_table = 'stop_time' app_label = 'multigtfs' _column_map = ( ('trip_id', 'trip__trip_id'), ('arrival_time', 'arrival_time'), ('departure_time', 'departure_time'), ('stop_id', 'stop__stop_id'), ('stop_sequence', 'stop_sequence'), ('stop_headsign', 'stop_headsign'), ('pickup_type', 'pickup_type'), ('drop_off_type', 'drop_off_type'), ('shape_dist_traveled', 'shape_dist_traveled') ) _filename = 'stop_times.txt' _rel_to_feed = 'trip__route__feed' _sort_order = ('trip__trip_id', 'stop_sequence') _unique_fields = ('trip_id', 'stop_sequence')
class Route(Base): """A transit route""" feed = models.ForeignKey('Feed') route_id = models.CharField( max_length=255, db_index=True, help_text="Unique identifier for route.") agency = models.ForeignKey( 'Agency', null=True, blank=True, help_text="Agency for this route.") short_name = models.CharField( max_length=10, help_text="Short name of the route") long_name = models.CharField( max_length=255, help_text="Long name of the route") desc = models.TextField( blank=True, help_text="Long description of a route") rtype = models.IntegerField( choices=((0, 'Tram, Streetcar, or Light rail'), (1, 'Subway or Metro'), (2, 'Rail'), (3, 'Bus'), (4, 'Ferry'), (5, 'Cable car'), (6, 'Gondola or Suspended cable car'), (7, 'Funicular')), help_text='Type of transportation used on route') url = models.URLField( blank=True, help_text="Web page about for the route") color = models.CharField( max_length=6, blank=True, help_text="Color of route in hex") text_color = models.CharField( max_length=6, blank=True, help_text="Color of route text in hex") def __unicode__(self): return u"%d-%s" % (self.feed.id, self.route_id) class Meta: db_table = 'route' app_label = 'multigtfs' _column_map = ( ('route_id', 'route_id'), ('agency_id', 'agency__agency_id'), ('route_short_name', 'short_name'), ('route_long_name', 'long_name'), ('route_desc', 'desc'), ('route_type', 'rtype'), ('route_url', 'url'), ('route_color', 'color'), ('route_text_color', 'text_color') ) _sort_order = ('route_id', 'short_name')
class Fare(Base): """A fare class""" feed = models.ForeignKey('Feed') fare_id = models.CharField(max_length=255, db_index=True, help_text="Unique identifier for a fare class") price = models.DecimalField( max_digits=17, decimal_places=4, help_text="Fare price, in units specified by currency_type") currency_type = models.CharField( max_length=3, help_text="ISO 4217 alphabetical currency code") payment_method = models.IntegerField( default=1, choices=((0, 'Fare is paid on board.'), (1, 'Fare must be paid before boarding.')), help_text="When is the fare paid?") transfers = models.IntegerField( default=None, null=True, blank=True, choices=((0, 'No transfers permitted on this fare.'), (1, 'Passenger may transfer once.'), (2, 'Passenger may transfer twice.'), (None, 'Unlimited transfers are permitted.')), help_text="Are transfers permitted?") transfer_duration = models.IntegerField( null=True, blank=True, help_text="Time in seconds until a ticket or transfer expires") extra_data = JSONField(default={}, blank=True, null=True) def __str__(self): return u"%d-%s(%s %s)" % (self.feed.id, self.fare_id, self.price, self.currency_type) class Meta: db_table = 'fare' app_label = 'multigtfs' # For Base import/export _column_map = (('fare_id', 'fare_id'), ('price', 'price'), ('currency_type', 'currency_type'), ('payment_method', 'payment_method'), ('transfers', 'transfers'), ('transfer_duration', 'transfer_duration')) _filename = 'fare_attributes.txt' _unique_fields = ('fare_id', )
class Frequency(Base): """Description of a trip that repeats without fixed stop times""" trip = models.ForeignKey('Trip') start_time = SecondsField( help_text="Time that the service begins at the specified frequency") end_time = SecondsField( help_text="Time that the service ends at the specified frequency") headway_secs = models.IntegerField( help_text="Time in seconds before returning to same stop") exact_times = models.CharField( max_length=1, blank=True, choices=((0, 'Trips are not exactly scheduled'), (1, 'Trips are exactly scheduled from start time')), help_text="Should frequency-based trips be exactly scheduled?") extra_data = JSONField(default={}, blank=True, null=True) def __str__(self): return str(self.trip) class Meta: db_table = 'frequency' app_label = 'multigtfs' verbose_name_plural = "frequencies" # For Base import/export _column_map = (('trip_id', 'trip__trip_id'), ('start_time', 'start_time'), ('end_time', 'end_time'), ('headway_secs', 'headway_secs'), ('exact_times', 'exact_times')) _filename = 'frequencies.txt' _rel_to_feed = 'trip__route__feed' _unique_fields = ('trip_id', 'start_time')
class Shape(Base): """The path the vehicle takes along the route. Implements shapes.txt.""" feed = models.ForeignKey('Feed', on_delete=models.CASCADE) shape_id = models.CharField( max_length=255, db_index=True, help_text="Unique identifier for a shape.") geometry = models.LineStringField( null=True, blank=True, help_text='Geometry cache of ShapePoints') def __str__(self): return "%d-%s" % (self.feed.id, self.shape_id) def update_geometry(self, update_parent=True): """Update the geometry from the related ShapePoints""" original = self.geometry points = self.points.order_by( 'sequence').values_list('point', flat=True) if len(points) > 1: self.geometry = LineString([pt.coords for pt in points]) if self.geometry != original: self.save() if update_parent: for trip in self.trip_set.all(): trip.update_geometry() class Meta: db_table = 'shape' app_label = 'multigtfs' _rel_to_feed = 'feed'
class Agency(Base): """One or more transit agencies that provide the data in this feed. Maps to agency.txt in the GTFS feed. """ feed = models.ForeignKey('Feed') agency_id = models.CharField( max_length=255, blank=True, db_index=True, help_text="Unique identifier for transit agency") name = models.CharField( max_length=255, help_text="Full name of the transit agency") url = models.URLField( blank=True, help_text="URL of the transit agency") timezone = models.CharField( max_length=255, help_text="Timezone of the agency") lang = models.CharField( max_length=2, blank=True, help_text="ISO 639-1 code for the primary language") phone = models.CharField( max_length=255, blank=True, help_text="Voice telephone number") fare_url = models.URLField( blank=True, help_text="URL for purchasing tickets online") extra_data = JSONField(default={}, blank=True, null=True) def __str__(self): return u"%d-%s" % (self.feed.id, self.agency_id) class Meta: db_table = 'agency' app_label = 'multigtfs' verbose_name_plural = "agencies" # GTFS column names to fields, used by Base for import/export _column_map = ( ('agency_id', 'agency_id'), ('agency_name', 'name'), ('agency_url', 'url'), ('agency_timezone', 'timezone'), ('agency_lang', 'lang'), ('agency_phone', 'phone'), ('agency_fare_url', 'fare_url') ) _filename = 'agency.txt' _unique_fields = ('agency_id',)
class Service(Base): """Dates that a route is active. Implements calendar.txt """ feed = models.ForeignKey('Feed', on_delete=models.CASCADE) service_id = models.CharField( max_length=255, db_index=True, help_text="Unique identifier for service dates.") monday = models.BooleanField(default=True, help_text="Is the route active on Monday?") tuesday = models.BooleanField(default=True, help_text="Is the route active on Tuesday?") wednesday = models.BooleanField( default=True, help_text="Is the route active on Wednesday?") thursday = models.BooleanField( default=True, help_text="Is the route active on Thursday?") friday = models.BooleanField(default=True, help_text="Is the route active on Friday?") saturday = models.BooleanField( default=True, help_text="Is the route active on Saturday?") sunday = models.BooleanField(default=True, help_text="Is the route active on Sunday?") start_date = models.DateField(null=True, blank=True) end_date = models.DateField(null=True, blank=True) extra_data = JSONField(default={}, blank=True, null=True) def __str__(self): return "%d-%s" % (self.feed.id, self.service_id) class Meta: db_table = 'gtfs_service' app_label = 'multigtfs' # For Base import/export _column_map = (('service_id', 'service_id'), ('monday', 'monday'), ('tuesday', 'tuesday'), ('wednesday', 'wednesday'), ('thursday', 'thursday'), ('friday', 'friday'), ('saturday', 'saturday'), ('sunday', 'sunday'), ('start_date', 'start_date'), ('end_date', 'end_date')) _filename = 'calendar.txt' _sort_order = ('start_date', 'end_date') _unique_fields = ('service_id', ) @classmethod def export_txt(cls, feed): '''Export records as calendar.txt''' # If no records with start/end dates, skip calendar.txt objects = cls.objects.in_feed(feed) if not objects.exclude(start_date__isnull=True, end_date__isnull=True).exists(): return None return super(Service, cls).export_txt(feed)
class FeedInfo(Base): """Information about the feed Implements feed_info.txt in the GTFS feed. """ feed = models.ForeignKey('Feed', on_delete=models.CASCADE) publisher_name = models.CharField( max_length=255, help_text="Full name of organization that publishes the feed.") publisher_url = models.URLField( help_text="URL of the feed publisher's organization.") lang = models.CharField( "language", max_length=20, help_text="IETF BCP 47 language code for text in field.") start_date = models.DateField( null=True, blank=True, help_text="Date that feed starts providing reliable data.") end_date = models.DateField( null=True, blank=True, help_text="Date that feed stops providing reliable data.") version = models.CharField(max_length=255, blank=True, help_text="Version of feed.") extra_data = JSONField(default={}, blank=True, null=True) def __str__(self): return '%s-%s' % (self.feed.id, self.publisher_name) class Meta: db_table = 'feed_info' app_label = 'multigtfs' verbose_name_plural = "feed info" _column_map = (('feed_publisher_name', 'publisher_name'), ('feed_publisher_url', 'publisher_url'), ('feed_lang', 'lang'), ('feed_start_date', 'start_date'), ('feed_end_date', 'end_date'), ('feed_version', 'version')) _filename = 'feed_info.txt' _unique_fields = ('feed_publisher_name', )
class NewStop(Base): """A stop captured during a ride To reference new stops data in the GTFS feed. """ ride = models.ForeignKey('Ride') latitude = models.CharField( max_length=255, blank=True, null=True, help_text='WGS 84 latitude of stop or station') longitude = models.CharField( max_length=255, blank=True, null=True, help_text='WGS 84 latitude of stop or station') arrival_time = models.CharField( max_length=255, blank=True, null=True, help_text='What time did the ride arrive?' ) departure_time = models.CharField( max_length=255, blank=True, null=True, help_text='What time did the ride arrive?' ) board = models.CharField( max_length=255, blank=True, null=True, ) alight = models.CharField( max_length=255, blank=True, null=True, ) extra_data = JSONField(default={}, blank=True, null=True) def __str__(self): return "%s %s" % (self.latitude, self.longitude)
class NewRoute(Base): """A stop captured during a ride To reference new stops data in the GTFS feed. """ ride = models.ForeignKey('Ride') latitude = models.CharField(max_length=255, blank=True, null=True, help_text='WGS 84 latitude of stop or station') longitude = models.CharField( max_length=255, blank=True, null=True, help_text='WGS 84 latitude of stop or station') time = models.CharField(max_length=255, blank=True, null=True, help_text='What time did the ride arrive?') def __str__(self): return "%s %s" % (self.latitude, self.longitude)
class Zone(Base): """Represents a fare zone. This data is not represented as a file in the GTFS. It appears as an identifier in the fare_rules and the stop tables. """ feed = models.ForeignKey('Feed') zone_id = models.CharField(max_length=10, db_index=True, help_text="Unique identifier for a zone.") class Meta: db_table = 'zone' app_label = 'multigtfs'
class Shape(Base): """The path the vehicle takes along the route""" feed = models.ForeignKey('Feed') shape_id = models.CharField( max_length=255, db_index=True, help_text="Unique identifier for a shape.") def __unicode__(self): return u"%d-%s" % (self.feed.id, self.shape_id) class Meta: db_table = 'shape' app_label = 'multigtfs' _rel_to_feed = 'feed'
class Service(Base): """Dates that a route is active.""" feed = models.ForeignKey('Feed') service_id = models.CharField( max_length=255, db_index=True, help_text="Unique identifier for service dates.") monday = models.BooleanField(default=True, help_text="Is the route active on Monday?") tuesday = models.BooleanField(default=True, help_text="Is the route active on Tuesday?") wednesday = models.BooleanField( default=True, help_text="Is the route active on Wednesday?") thursday = models.BooleanField( default=True, help_text="Is the route active on Thursday?") friday = models.BooleanField(default=True, help_text="Is the route active on Friday?") saturday = models.BooleanField( default=True, help_text="Is the route active on Saturday?") sunday = models.BooleanField(default=True, help_text="Is the route active on Sunday?") start_date = models.DateField( default=datetime.strptime('18991231', '%Y%m%d')) end_date = models.DateField( default=datetime.strptime('21000101', '%Y%m%d')) def __unicode__(self): return u"%d-%s" % (self.feed.id, self.service_id) class Meta: db_table = 'multigtfs_service' app_label = 'multigtfs' # For Base import/export _column_map = (('service_id', 'service_id'), ('monday', 'monday'), ('tuesday', 'tuesday'), ('wednesday', 'wednesday'), ('thursday', 'thursday'), ('friday', 'friday'), ('saturday', 'saturday'), ('sunday', 'sunday'), ('start_date', 'start_date'), ('end_date', 'end_date')) _sort_order = ('start_date', 'end_date') # support commonly out-of-date GTFS feed data # {'old csv name': 'django field name'} _legacy_format = { 'service_name': 'service_id', }
class Block(Base): """Represents a fare zone. This data is not represented as a file in the GTFS. It appears as an identifier in the trip table. """ feed = models.ForeignKey('Feed') block_id = models.CharField(max_length=63, db_index=True, help_text="Unique identifier for a block.") def __str__(self): return u"%d-%s" % (self.feed.id, self.block_id) class Meta: db_table = 'block' app_label = 'multigtfs'
class Zone(Base): """Represents a fare zone. This data is not represented as a file in the GTFS. It appears as an identifier in the fare_rules and the stop tables. """ feed = models.ForeignKey('Feed', on_delete=models.CASCADE) zone_id = models.CharField(max_length=63, db_index=True, help_text="Unique identifier for a zone.") def __str__(self): return "%d-%s" % (self.feed_id, self.zone_id) class Meta: db_table = 'zone' app_label = 'multigtfs'
class Service(Base): """Dates that a route is active.""" feed = models.ForeignKey('Feed') service_id = models.CharField( max_length=255, db_index=True, help_text="Unique identifier for service dates.") monday = models.BooleanField(default=True, help_text="Is the route active on Monday?") tuesday = models.BooleanField(default=True, help_text="Is the route active on Tuesday?") wednesday = models.BooleanField( default=True, help_text="Is the route active on Wednesday?") thursday = models.BooleanField( default=True, help_text="Is the route active on Thursday?") friday = models.BooleanField(default=True, help_text="Is the route active on Friday?") saturday = models.BooleanField( default=True, help_text="Is the route active on Saturday?") sunday = models.BooleanField(default=True, help_text="Is the route active on Sunday?") start_date = models.DateField() end_date = models.DateField() extra_data = JSONField(default={}, blank=True, null=True) def __str__(self): return "%d-%s" % (self.feed.id, self.service_id) class Meta: db_table = 'service' app_label = 'multigtfs' # For Base import/export _column_map = (('service_id', 'service_id'), ('monday', 'monday'), ('tuesday', 'tuesday'), ('wednesday', 'wednesday'), ('thursday', 'thursday'), ('friday', 'friday'), ('saturday', 'saturday'), ('sunday', 'sunday'), ('start_date', 'start_date'), ('end_date', 'end_date')) _filename = 'calendar.txt' _sort_order = ('start_date', 'end_date') _unique_fields = ('service_id', )
class Stop(Base): """A stop or station""" feed = models.ForeignKey('Feed') stop_id = models.CharField( max_length=255, db_index=True, help_text="Unique identifier for a stop or station.") code = models.CharField( max_length=255, blank=True, help_text="Uniquer identifier (short text or number) for passengers.") name = models.CharField(max_length=255, help_text="Name of stop in local vernacular.") desc = models.CharField(max_length=255, blank=True, help_text='Description of a stop.') point = models.PointField( geography=MULTIGTFS_USE_GEOGRAPHY, srid=MULTIGTFS_SRID, help_text='WGS 84 latitude/longitude of stop or station') zone = models.ForeignKey('Zone', null=True, blank=True, help_text="Fare zone for a stop ID.") url = models.URLField(blank=True, help_text="URL for the stop") location_type = models.CharField(max_length=1, blank=True, choices=(('0', 'Stop'), ('1', 'Station')), help_text="Is this a stop or station?") parent_station = models.ForeignKey( 'Stop', null=True, blank=True, help_text="The station associated with the stop") timezone = models.CharField(max_length=255, blank=True, help_text="Timezone of the stop") wheelchair_boarding = models.CharField( max_length=1, blank=True, choices=(('0', '0'), ('1', '1'), ('2', '2')), help_text= "Whether wheelchair boardings are possible from the specified stop or station" ) def __unicode__(self): return u"%d-%s" % (self.feed.id, self.stop_id) def getlon(self): return self.point[0] if self.point else 0.0 def setlon(self, value): if self.point: self.point[0] = value else: self.point = "POINT(%s 0)" % value lon = property(getlon, setlon, doc="WGS 84 longitude of stop or station") def getlat(self): return self.point[1] if self.point else 0.0 def setlat(self, value): if self.point: self.point[1] = value else: self.point = "POINT(0 %s)" % value lat = property(getlat, setlat, doc="WGS 84 latitude of stop or station") def __init__(self, *args, **kwargs): lat = kwargs.pop('lat', None) lon = kwargs.pop('lon', None) if lat is not None or lon is not None: assert kwargs.get('point') is None msg = "Setting Stop location with lat and lon is deprecated" warnings.warn(msg, DeprecationWarning) kwargs['point'] = "POINT(%s %s)" % (lon or 0.0, lat or 0.0) super(Stop, self).__init__(*args, **kwargs) class Meta: db_table = 'stop' app_label = 'multigtfs' _column_map = (('stop_id', 'stop_id'), ('stop_code', 'code'), ('stop_name', 'name'), ('stop_desc', 'desc'), ('stop_lat', 'point[1]'), ('stop_lon', 'point[0]'), ('zone_id', 'zone__zone_id'), ('stop_url', 'url'), ('location_type', 'location_type'), ('parent_station', 'parent_station__stop_id'), ('stop_timezone', 'timezone'), ('wheelchair_boarding', 'wheelchair_boarding')) @classmethod def import_txt(cls, txt_file, feed): '''Import from a stops.txt file Stations need to be imported before stops ''' def writeheader(writer): ''' Write the header row for a DictWriter CSV file This is a member function of DictWriter in Python 2.7 ''' writer.writerow(dict((fn, fn) for fn in writer.fieldnames)) txt = txt_file.read() fieldnames, _ = zip(*cls._column_map) has_stations = False stations_csv = StringIO.StringIO() stations = DictWriter(stations_csv, fieldnames) has_stops = False stops_csv = StringIO.StringIO() stops = DictWriter(stops_csv, fieldnames) for row in DictReader(StringIO.StringIO(txt)): if row.get('location_type') == '1': if not has_stations: writeheader(stations) has_stations = True stations.writerow(row) else: if not has_stops: writeheader(stops) has_stops = True stops.writerow(row) if has_stations: super(Stop, cls).import_txt(StringIO.StringIO(stations_csv.getvalue()), feed) if has_stops: super(Stop, cls).import_txt(StringIO.StringIO(stops_csv.getvalue()), feed)
class Trip(Base): """A trip along a route This implements trips.txt in the GTFS feed """ route = models.ForeignKey('Route', on_delete=models.CASCADE) service = models.ForeignKey('Service', null=True, blank=True, on_delete=models.SET_NULL) trip_id = models.CharField(max_length=255, db_index=True, help_text="Unique identifier for a trip.") headsign = models.CharField( max_length=255, blank=True, help_text="Destination identification for passengers.") short_name = models.CharField( max_length=63, blank=True, help_text="Short name used in schedules and signboards.") direction = models.CharField( max_length=1, blank=True, choices=(('0', '0'), ('1', '1')), help_text="Direction for bi-directional routes.") block = models.ForeignKey( 'Block', null=True, blank=True, on_delete=models.SET_NULL, help_text="Block of sequential trips that this trip belongs to.") wheelchair_accessible = models.CharField( max_length=1, blank=True, choices=(('0', 'No information'), ('1', 'Some wheelchair accommodation'), ('2', 'No wheelchair accommodation')), help_text='Are there accommodations for riders with wheelchair?') bikes_allowed = models.CharField(max_length=1, blank=True, choices=(('0', 'No information'), ('1', 'Some bicycle accommodation'), ('2', 'No bicycles allowed')), help_text='Are bicycles allowed?') extra_data = JSONField(default={}, blank=True, null=True) def __str__(self): return "%s-%s" % (self.route, self.trip_id) class Meta: db_table = 'gtfs_trip' app_label = 'multigtfs' _column_map = ( ('route_id', 'route__route_id'), ('service_id', 'service__service_id'), ('trip_id', 'trip_id'), ('trip_headsign', 'headsign'), ('trip_short_name', 'short_name'), ('direction_id', 'direction'), ('block_id', 'block__block_id'), ('wheelchair_accessible', 'wheelchair_accessible'), ('bikes_allowed', 'bikes_allowed'), ) _filename = 'trips.txt' _rel_to_feed = 'route__feed' _unique_fields = ('trip_id', )
class Trip(Base): """A trip along a route This implements trips.txt in the GTFS feed """ route = models.ForeignKey('Route', on_delete=models.CASCADE) service = models.ForeignKey('Service', null=True, blank=True, on_delete=models.SET_NULL) trip_id = models.CharField(max_length=255, db_index=True, help_text="Unique identifier for a trip.") headsign = models.CharField( max_length=255, blank=True, help_text="Destination identification for passengers.") short_name = models.CharField( max_length=63, blank=True, help_text="Short name used in schedules and signboards.") direction = models.CharField( max_length=1, blank=True, choices=(('0', '0'), ('1', '1')), help_text="Direction for bi-directional routes.") block = models.ForeignKey( 'Block', null=True, blank=True, on_delete=models.SET_NULL, help_text="Block of sequential trips that this trip belongs to.") shape = models.ForeignKey('Shape', null=True, blank=True, on_delete=models.SET_NULL, help_text="Shape used for this trip") geometry = models.LineStringField( null=True, blank=True, help_text='Geometry cache of Shape or Stops') wheelchair_accessible = models.CharField( max_length=1, blank=True, choices=(('0', 'No information'), ('1', 'Some wheelchair accommodation'), ('2', 'No wheelchair accommodation')), help_text='Are there accommodations for riders with wheelchair?') bikes_allowed = models.CharField(max_length=1, blank=True, choices=(('0', 'No information'), ('1', 'Some bicycle accommodation'), ('2', 'No bicycles allowed')), help_text='Are bicycles allowed?') extra_data = JSONField(default={}, blank=True, null=True) def update_geometry(self, update_parent=True): """Update the geometry from the Shape or Stops""" original = self.geometry if self.shape: self.geometry = self.shape.geometry else: stoptimes = self.stoptime_set.order_by('stop_sequence') if stoptimes.count() > 1: self.geometry = LineString( [st.stop.point.coords for st in stoptimes]) if self.geometry != original: self.save() if update_parent: self.route.update_geometry() def __str__(self): return "%s-%s" % (self.route, self.trip_id) class Meta: db_table = 'trip' app_label = 'multigtfs' _column_map = ( ('route_id', 'route__route_id'), ('service_id', 'service__service_id'), ('trip_id', 'trip_id'), ('trip_headsign', 'headsign'), ('trip_short_name', 'short_name'), ('direction_id', 'direction'), ('block_id', 'block__block_id'), ('shape_id', 'shape__shape_id'), ('wheelchair_accessible', 'wheelchair_accessible'), ('bikes_allowed', 'bikes_allowed'), ) _filename = 'trips.txt' _rel_to_feed = 'route__feed' _unique_fields = ('trip_id', )
class NewFare(Base): """A new fare entry """ stop_to = models.CharField( max_length=255, blank=True, null=True,) stop_from = models.CharField( max_length=255, blank=True, null=True,) amount = models.CharField( max_length=255, blank=True, null=True,) stop_from_id = models.CharField( max_length=255, blank=True, null=True,) route_id = models.CharField( max_length=255, blank=True, null=True,) stop_to_id = models.CharField( max_length=255, blank=True, null=True,) weather = models.CharField( max_length=255, blank=True, null=True,) traffic_jam = models.CharField( max_length=255, blank=True, null=True,) demand = models.CharField( max_length=255, blank=True, null=True,) rush_hour = models.CharField( max_length=255, blank=True, null=True,) peak = models.CharField( max_length=255, blank=True, null=True,) travel_time = models.CharField( max_length=255, blank=True, null=True,) crowd = models.CharField( max_length=255, blank=True, null=True,) safety = models.CharField( max_length=255, blank=True, null=True,) drive_safety = models.CharField( max_length=255, blank=True, null=True,) music = models.CharField( max_length=255, blank=True, null=True,) internet = models.CharField( max_length=255, blank=True, null=True,) def __str__(self): return "%s %s %s" % (self.stop_to, self.stop_from, self.amount)
class Stop(Base): """A stop or station""" feed = models.ForeignKey('Feed') stop_id = models.CharField( max_length=255, db_index=True, help_text="Unique identifier for a stop or station.") code = models.CharField( max_length=255, blank=True, help_text="Uniquer identifier (short text or number) for passengers.") name = models.CharField(max_length=255, help_text="Name of stop in local vernacular.") desc = models.CharField("description", max_length=255, blank=True, help_text='Description of a stop.') point = models.PointField( help_text='WGS 84 latitude/longitude of stop or station') zone = models.ForeignKey('Zone', null=True, blank=True, help_text="Fare zone for a stop ID.") url = models.URLField(blank=True, help_text="URL for the stop") location_type = models.CharField(max_length=1, blank=True, choices=(('0', 'Stop'), ('1', 'Station')), help_text="Is this a stop or station?") parent_station = models.ForeignKey( 'Stop', null=True, blank=True, help_text="The station associated with the stop") timezone = models.CharField(max_length=255, blank=True, help_text="Timezone of the stop") wheelchair_boarding = models.CharField( max_length=1, blank=True, choices=(('0', 'No information'), ('1', 'Some wheelchair boarding'), ('2', 'No wheelchair boarding')), help_text='Is wheelchair boarding possible?') extra_data = JSONField(default={}, blank=True, null=True) def __str__(self): return "%d-%s" % (self.feed_id, self.stop_id) def getlon(self): return self.point[0] if self.point else 0.0 def setlon(self, value): if self.point: self.point[0] = value else: self.point = "POINT(%s 0)" % value lon = property(getlon, setlon, doc="WGS 84 longitude of stop or station") def getlat(self): return self.point[1] if self.point else 0.0 def setlat(self, value): if self.point: self.point[1] = value else: self.point = "POINT(0 %s)" % value lat = property(getlat, setlat, doc="WGS 84 latitude of stop or station") def __init__(self, *args, **kwargs): lat = kwargs.pop('lat', None) lon = kwargs.pop('lon', None) if lat is not None or lon is not None: assert kwargs.get('point') is None msg = "Setting Stop location with lat and lon is deprecated" warnings.warn(msg, DeprecationWarning) kwargs['point'] = "POINT(%s %s)" % (lon or 0.0, lat or 0.0) super(Stop, self).__init__(*args, **kwargs) class Meta: db_table = 'stop' app_label = 'multigtfs' _column_map = ( ('stop_id', 'stop_id'), ('stop_code', 'code'), ('stop_name', 'name'), ('stop_desc', 'desc'), ('stop_lat', 'point[1]'), ('stop_lon', 'point[0]'), ('zone_id', 'zone__zone_id'), ('stop_url', 'url'), ('location_type', 'location_type'), ('parent_station', 'parent_station__stop_id'), ('stop_timezone', 'timezone'), ('wheelchair_boarding', 'wheelchair_boarding'), ) _filename = 'stops.txt' _unique_fields = ('stop_id', ) @classmethod def import_txt(cls, txt_file, feed): '''Import from a stops.txt file Stations need to be imported before stops ''' txt = txt_file.read() def is_station(pairs): '''Does the row represent a station?''' for name, val in pairs: if name == 'location_type': return val == '1' return False logger.info("Importing station stops") stations = super(Stop, cls).import_txt(StringIO(txt), feed, is_station) logger.info("Imported %d station stops", stations) def is_stop(pairs): '''Does the row represent a stop?''' for name, val in pairs: if name == 'location_type': return val != '1' return True logger.info("Importing non-station stops") stops = super(Stop, cls).import_txt(StringIO(txt), feed, is_stop) logger.info("Imported %d non-station stops", stops) return stations + stops
class Route(Base): """A transit route""" feed = models.ForeignKey('Feed') route_id = models.CharField(max_length=255, db_index=True, help_text="Unique identifier for route.") agency = models.ForeignKey('Agency', null=True, blank=True, help_text="Agency for this route.") short_name = models.CharField(max_length=63, help_text="Short name of the route") long_name = models.CharField(max_length=255, help_text="Long name of the route") desc = models.TextField(blank=True, help_text="Long description of a route") rtype = models.IntegerField( choices=((0, 'Tram, Streetcar, or Light rail'), (1, 'Subway or Metro'), (2, 'Rail'), (3, 'Bus'), (4, 'Ferry'), (5, 'Cable car'), (6, 'Gondola or Suspended cable car'), (7, 'Funicular')), help_text='Type of transportation used on route') url = models.URLField(blank=True, help_text="Web page about for the route") color = models.CharField(max_length=6, blank=True, help_text="Color of route in hex") text_color = models.CharField(max_length=6, blank=True, help_text="Color of route text in hex") geometry = models.MultiLineStringField(null=True, blank=True, help_text='Geometry cache of Trips') def update_geometry(self): """Update the geometry from the Trips""" original = self.geometry trips = self.trip_set.exclude(geometry=None) unique_coords = set() unique_geom = list() for t in trips: coords = t.geometry.coords if coords not in unique_coords: unique_coords.add(coords) unique_geom.append(t.geometry) self.geometry = MultiLineString(unique_geom) if self.geometry != original: self.save() def __unicode__(self): return u"%d-%s" % (self.feed.id, self.route_id) def stop_set(self): stoptimes = itertools.chain(*[ trip.stoptime_set.all().distinct('stop') for trip in self.trip_set.all() ]) return set([stoptime.stop for stoptime in stoptimes]) class Meta: db_table = 'multigtfs_route' app_label = 'multigtfs' _column_map = (('route_id', 'route_id'), ('agency_id', 'agency__agency_id'), ('route_short_name', 'short_name'), ('route_long_name', 'long_name'), ('route_desc', 'desc'), ('route_type', 'rtype'), ('route_url', 'url'), ('route_color', 'color'), ('route_text_color', 'text_color')) _sort_order = ('route_id', 'short_name')
class Route(Base): """A transit route Maps to route.txt in the GTFS feed. """ feed = models.ForeignKey('Feed', on_delete=models.CASCADE) route_id = models.CharField(max_length=255, db_index=True, help_text="Unique identifier for route.") agency = models.ForeignKey('Agency', null=True, blank=True, on_delete=models.SET_NULL, help_text="Agency for this route.") short_name = models.CharField(max_length=63, help_text="Short name of the route") long_name = models.CharField(max_length=255, help_text="Long name of the route") desc = models.TextField("description", blank=True, help_text="Long description of a route") rtype = models.IntegerField( "route type", choices=((0, 'Tram, Streetcar, or Light rail'), (1, 'Subway or Metro'), (2, 'Rail'), (3, 'Bus'), (4, 'Ferry'), (5, 'Cable car'), (6, 'Gondola or Suspended cable car'), (7, 'Funicular')), help_text='Type of transportation used on route') url = models.URLField(blank=True, help_text="Web page about for the route") color = models.CharField(max_length=6, blank=True, help_text="Color of route in hex") text_color = models.CharField(max_length=6, blank=True, help_text="Color of route text in hex") geometry = models.MultiLineStringField(null=True, blank=True, help_text='Geometry cache of Trips') extra_data = JSONField(default={}, blank=True, null=True) def update_geometry(self): """Update the geometry from the Trips""" original = self.geometry trips = self.trip_set.exclude(geometry__isnull=True) unique_coords = set() unique_geom = list() for t in trips: coords = t.geometry.coords if coords not in unique_coords: unique_coords.add(coords) unique_geom.append(t.geometry) self.geometry = MultiLineString(unique_geom) if self.geometry != original: self.save() def __str__(self): return "%d-%s" % (self.feed.id, self.route_id) class Meta: db_table = 'route' app_label = 'multigtfs' _column_map = (('route_id', 'route_id'), ('agency_id', 'agency__agency_id'), ('route_short_name', 'short_name'), ('route_long_name', 'long_name'), ('route_desc', 'desc'), ('route_type', 'rtype'), ('route_url', 'url'), ('route_color', 'color'), ('route_text_color', 'text_color')) _filename = 'routes.txt' _sort_order = ('route_id', 'short_name') _unique_fields = ('route_id', )