Skip to content

Commit 9d8741d

Browse files
committed
databox lap
1 parent 697d117 commit 9d8741d

File tree

2 files changed

+172
-1
lines changed

2 files changed

+172
-1
lines changed

paddock/templates/sessions.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ <h5 class="card-title">
3737
<td>
3838
<a href="{% url 'session' session_id=session.session_id lap=lap.number %}" class="btn btn-primary">View</a>
3939
<a href="{% url 'lap' lap_id=lap.pk %}" class="btn btn-secondary">Stats</a>
40-
<a href="https://databox.b4mad.racing/session/{{ session.session_id }}/{{ lap.number }}" class="btn btn-info" target="_blank">DataBox</a>
40+
<a href="https://databox.b4mad.racing/session/{{ session.session_id }}?lap={{ lap.number }}" class="btn btn-info" target="_blank">DataBox</a>
4141
</td>
4242
<td>{{ lap.number }}</td>
4343
<td>{{ lap.start }}</td>

telemetry/racing_stats.py

+171
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,54 @@
99

1010
class RacingStats:
1111
def __init__(self, using="default"):
12+
"""Initialize RacingStats with database connection.
13+
14+
Args:
15+
using (str, optional): Database connection to use. Defaults to "default".
16+
"""
1217
self.using = using
1318
pass
1419

1520
def combos(self, type="", **kwargs):
21+
"""Convenience method that calls driver_combos().
22+
23+
Args:
24+
type (str, optional): Type of racing to filter for ("circuit" or "rally"). Defaults to "".
25+
**kwargs: Additional arguments passed to driver_combos().
26+
27+
Returns:
28+
QuerySet: Results from driver_combos().
29+
"""
1630
return self.driver_combos(type=type, **kwargs)
1731

1832
def driver_combos(self, driver=None, range=30, type="circuit", **kwargs):
33+
"""Get combinations of game/track/car with statistics.
34+
35+
Args:
36+
driver (str, optional): Filter by driver name. Defaults to None.
37+
range (int, optional): Number of days to look back. Defaults to 30.
38+
type (str, optional): Type of racing to filter for:
39+
- "circuit": Only circuit racing games
40+
- "rally": Only rally games
41+
- "": All games
42+
**kwargs: Additional filter arguments
43+
44+
Returns:
45+
QuerySet: Contains for each combo:
46+
- session__game__name: Game name
47+
- track__name: Track name ("Multiple" for rally)
48+
- car__name: Car name
49+
- lap_count: Total number of laps
50+
- valid_lap_count: Number of valid laps
51+
- latest_lap_end: Most recent lap end time
52+
53+
Example:
54+
>>> stats = RacingStats()
55+
>>> # Get circuit combos for last 7 days
56+
>>> circuit_combos = stats.driver_combos(range=7, type="circuit")
57+
>>> # Get rally combos for specific driver
58+
>>> rally_combos = stats.driver_combos(driver="John", type="rally")
59+
"""
1960
filter = {}
2061
if driver is not None:
2162
filter["session__driver__name"] = driver
@@ -55,11 +96,48 @@ def driver_combos(self, driver=None, range=30, type="circuit", **kwargs):
5596
return laps
5697

5798
def known_combos_list(self, game=None, track=None, car=None, **kwargs):
99+
"""Generator yielding tuples of known game/car/track combinations.
100+
101+
Args:
102+
game (str, optional): Filter by game name. Defaults to None.
103+
track (str, optional): Filter by track name. Defaults to None.
104+
car (str, optional): Filter by car name. Defaults to None.
105+
**kwargs: Additional filter arguments
106+
107+
Yields:
108+
tuple: (game_name, car_name, track_name, lap_count)
109+
110+
Example:
111+
>>> stats = RacingStats()
112+
>>> # List all AC combos
113+
>>> for game, car, track, count in stats.known_combos_list(game="Assetto Corsa"):
114+
... print(f"{car} on {track}: {count} laps")
115+
"""
58116
laps = self.known_combos(game, track, car, **kwargs)
59117
for row in laps:
60118
yield row["track__game__name"], row["car__name"], row["track__name"], row["count"]
61119

62120
def known_combos(self, game=None, track=None, car=None, **kwargs):
121+
"""Get known combinations of game/car/track with valid lap counts.
122+
123+
Args:
124+
game (str, optional): Filter by game name. Defaults to None.
125+
track (str, optional): Filter by track name. Defaults to None.
126+
car (str, optional): Filter by car name. Defaults to None.
127+
**kwargs: Additional filter arguments
128+
129+
Returns:
130+
QuerySet: Contains for each combo:
131+
- track__name: Track name
132+
- car__name: Car name
133+
- track__game__name: Game name
134+
- count: Number of valid laps
135+
136+
Example:
137+
>>> stats = RacingStats()
138+
>>> # Get all GT3 car combos
139+
>>> gt3_combos = stats.known_combos(car="GT3")
140+
"""
63141
filter = {}
64142
if game:
65143
filter["track__game__name"] = game
@@ -77,6 +155,25 @@ def known_combos(self, game=None, track=None, car=None, **kwargs):
77155
return laps
78156

79157
def fast_lap_values(self, game=None, track=None, car=None, **kwargs):
158+
"""Get combinations that have fast lap records.
159+
160+
Args:
161+
game (str, optional): Filter by game name. Defaults to None.
162+
track (str, optional): Filter by track name. Defaults to None.
163+
car (str, optional): Filter by car name. Defaults to None.
164+
**kwargs: Additional filter arguments
165+
166+
Returns:
167+
QuerySet: Contains for each combo:
168+
- track__name: Track name
169+
- car__name: Car name
170+
- game__name: Game name
171+
172+
Example:
173+
>>> stats = RacingStats()
174+
>>> # Get all fast lap combos for Spa
175+
>>> spa_records = stats.fast_lap_values(track="Spa")
176+
"""
80177
filter = {}
81178
if game:
82179
filter["game__name"] = game
@@ -97,6 +194,24 @@ def fast_lap_values(self, game=None, track=None, car=None, **kwargs):
97194
# yield row["track__game__name"], row["car__name"], row["track__name"], row["count"]
98195

99196
def fast_laps(self, game=None, track=None, car=None, **kwargs):
197+
"""Get FastLap records for a specific game/track/car combination.
198+
199+
Args:
200+
game (str): Game name to filter by
201+
track (str): Track name to filter by
202+
car (str): Car name to filter by
203+
**kwargs: Additional filter arguments
204+
205+
Returns:
206+
QuerySet[FastLap]: Matching FastLap records
207+
208+
Example:
209+
>>> stats = RacingStats()
210+
>>> # Get fastest laps for GT3 cars at Spa in AC
211+
>>> records = stats.fast_laps(game="Assetto Corsa",
212+
... track="Spa",
213+
... car="GT3")
214+
"""
100215
filter = {}
101216
filter["game__name"] = game
102217
filter["track__name"] = track
@@ -106,6 +221,24 @@ def fast_laps(self, game=None, track=None, car=None, **kwargs):
106221
return laps
107222

108223
def laps(self, game=None, track=None, car=None, driver=None, valid=None, **kwargs):
224+
"""Get lap records filtered by various criteria.
225+
226+
Args:
227+
game (str, optional): Filter by game name. Defaults to None.
228+
track (str, optional): Filter by track name. Defaults to None.
229+
car (str, optional): Filter by car name. Defaults to None.
230+
driver (str, optional): Filter by driver name. Defaults to None.
231+
valid (bool, optional): Filter by lap validity. Defaults to None.
232+
**kwargs: Additional filter arguments
233+
234+
Returns:
235+
QuerySet[Lap]: Matching Lap records, ordered by time
236+
237+
Example:
238+
>>> stats = RacingStats()
239+
>>> # Get all valid laps by a driver
240+
>>> driver_laps = stats.laps(driver="John", valid=True)
241+
"""
109242
filter = {}
110243
if game:
111244
filter["track__game__name"] = game
@@ -130,6 +263,26 @@ def laps(self, game=None, track=None, car=None, driver=None, valid=None, **kwarg
130263
# yield lap
131264

132265
def sessions(self, game=None, track=None, car=None, driver=None, session_ids=None, **kwargs):
266+
"""Get racing sessions filtered by various criteria.
267+
268+
Args:
269+
game (str, optional): Filter by game name. Defaults to None.
270+
track (str, optional): Filter by track name. Defaults to None.
271+
car (str, optional): Filter by car name. Defaults to None.
272+
driver (str, optional): Filter by driver name. Defaults to None.
273+
session_ids (list, optional): Filter by specific session IDs. Defaults to None.
274+
**kwargs: Additional filter arguments
275+
276+
Returns:
277+
QuerySet[Session]: Matching Session records, ordered by start time
278+
279+
Example:
280+
>>> stats = RacingStats()
281+
>>> # Get all sessions for a specific driver
282+
>>> driver_sessions = stats.sessions(driver="John")
283+
>>> # Get specific sessions by ID
284+
>>> specific_sessions = stats.sessions(session_ids=[1,2,3])
285+
"""
133286
filter = {}
134287
if game:
135288
filter["game__name"] = game
@@ -148,6 +301,24 @@ def sessions(self, game=None, track=None, car=None, driver=None, session_ids=Non
148301
return sessions
149302

150303
def fast_laps_cursor(self, game=None, track=None, car=None, **kwargs):
304+
"""Get lap counts by track and car using direct database cursor.
305+
306+
Uses raw SQL for potentially better performance when getting aggregate counts.
307+
308+
Args:
309+
game (str, optional): Filter by game name. Defaults to None.
310+
track (str, optional): Filter by track name. Defaults to None.
311+
car (str, optional): Filter by car name. Defaults to None.
312+
**kwargs: Additional filter arguments
313+
314+
Returns:
315+
list[tuple]: Each tuple contains (count, track_id, car_id)
316+
317+
Example:
318+
>>> stats = RacingStats()
319+
>>> # Get lap counts for all track/car combos in AC
320+
>>> counts = stats.fast_laps_cursor(game="Assetto Corsa")
321+
"""
151322
where = []
152323
filter_game = None
153324
if game:

0 commit comments

Comments
 (0)