Skip to content

Commit 8f1f3e5

Browse files
authored
Merge pull request #1975 from wger-project/feature/ingredient-sync-log
Improve logging for ingredient sync operations
2 parents 9d5951f + 874daa7 commit 8f1f3e5

File tree

3 files changed

+67
-43
lines changed

3 files changed

+67
-43
lines changed

wger/nutrition/management/commands/sync-ingredients.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,16 @@ def handle(self, **options):
5050

5151
check_min_server_version(remote_url)
5252
try:
53-
self.languages = languages
54-
if self.languages is not None:
55-
for language in self.languages.split(','):
53+
if languages is not None:
54+
for language in languages.split(','):
5655
validate_language_code(language)
5756
except ValidationError as e:
5857
raise CommandError('\n'.join([str(arg) for arg in e.args if arg is not None]))
5958

60-
sync_ingredients(self.stdout.write, self.remote_url, self.languages, self.style.SUCCESS)
59+
sync_ingredients(
60+
self.stdout.write,
61+
self.remote_url,
62+
languages,
63+
self.style.SUCCESS,
64+
show_progress_bar=True
65+
)

wger/nutrition/sync.py

Lines changed: 51 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
AWS_S3_BASE_URL,
3232
generate_image_path,
3333
)
34+
from tqdm import tqdm
3435

3536
# wger
3637
from wger.core.models.language import Language
@@ -247,54 +248,71 @@ def sync_ingredients(
247248
remote_url=settings.WGER_SETTINGS['WGER_INSTANCE'],
248249
language_codes: Optional[str] = None,
249250
style_fn=lambda x: x,
251+
show_progress_bar: bool = False,
250252
):
251253
"""Synchronize the ingredients from the remote server"""
252-
253-
def _sync_ingredients(language_codes: Optional[int] = None):
254-
if language_codes is not None:
255-
url = make_uri(
256-
INGREDIENTS_ENDPOINT,
257-
server_url=remote_url,
258-
query={'limit': API_MAX_ITEMS, 'language__in': language_codes},
259-
)
260-
else:
261-
url = make_uri(
262-
INGREDIENTS_ENDPOINT,
263-
server_url=remote_url,
264-
query={'limit': API_MAX_ITEMS},
265-
)
266-
for data in get_paginated(url, headers=wger_headers()):
267-
uuid = data['uuid']
268-
name = data['name']
269-
270-
ingredient_data = extract_info_from_wger_api(data).dict()
271-
ingredient_data['uuid'] = uuid
272-
273-
ingredient, created = Ingredient.objects.update_or_create(
274-
uuid=uuid, defaults=ingredient_data
275-
)
276-
277-
print_fn(f'{"created" if created else "updated"} ingredient {uuid} - {name}')
278-
279254
print_fn('*** Synchronizing ingredients...')
280255

256+
language_ids: List[str] | None = None
281257
if language_codes is not None:
282-
language_ids: List[int] = []
258+
language_ids = []
283259
for code in language_codes.split(','):
284260
# Leaving the try except in here even though we've already validated on the sync-ingredients command itself.
285261
# This is in case we ever want to re-use this function for anything else where user can input language codes.
286262
try:
287263
lang = load_language(code, default_to_english=False)
288-
language_ids.append(lang.id)
264+
language_ids.append(str(lang.id))
289265
except Language.DoesNotExist as e:
290266
print_fn(
291267
f'Error: The language code you provided ("{code}") does not exist in this database. Please try again.'
292268
)
293269
return 0
294270

295-
for language_id in language_ids:
296-
_sync_ingredients(language_id)
297-
else:
298-
_sync_ingredients()
271+
query: dict[str, str | int] = {'limit': API_MAX_ITEMS}
272+
if language_ids is not None:
273+
query['language__in'] = ','.join(language_ids)
274+
275+
url = make_uri(
276+
INGREDIENTS_ENDPOINT,
277+
server_url=remote_url,
278+
query=query,
279+
)
280+
281+
# Fetch once to retrieve the number of results
282+
response = requests.get(url, headers=wger_headers()).json()
283+
total_ingredients = response['count']
284+
total_pages = total_ingredients // API_MAX_ITEMS
285+
286+
ingredient_nr = 1
287+
page_nr = 1
288+
pbar = tqdm(
289+
total=total_ingredients,
290+
unit='ingredients',
291+
desc='Syncing progress',
292+
unit_scale=True
293+
)
294+
for data in get_paginated(url, headers=wger_headers()):
295+
uuid = data['uuid']
296+
297+
ingredient_data = extract_info_from_wger_api(data).dict()
298+
ingredient_data['uuid'] = uuid
299+
300+
Ingredient.objects.update_or_create(
301+
uuid=uuid,
302+
defaults=ingredient_data
303+
)
304+
305+
if show_progress_bar:
306+
pbar.update(1)
307+
else:
308+
# Note that get_paginated returns the individual result entries from the pages.
309+
# To get the current page, we need to calculate this ourselves.
310+
ingredient_nr += 1
311+
if ingredient_nr % API_MAX_ITEMS == 0:
312+
page_nr += 1
313+
print_fn(f'Processing ingredients, page {page_nr: >4} of {total_pages}')
314+
315+
pbar.close()
299316

300317
print_fn(style_fn('done!\n'))
318+
return None

wger/nutrition/tasks.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,12 @@
1919
randint,
2020
)
2121

22-
# Django
23-
from django.conf import settings
24-
from django.core.management import call_command
25-
2622
# Third Party
2723
from celery import shared_task
2824
from celery.schedules import crontab
25+
# Django
26+
from django.conf import settings
27+
from django.core.management import call_command
2928

3029
# wger
3130
from wger.celery_configuration import app
@@ -35,7 +34,6 @@
3534
sync_ingredients,
3635
)
3736

38-
3937
logger = logging.getLogger(__name__)
4038

4139

@@ -64,7 +62,10 @@ def sync_all_ingredients_task():
6462
"""
6563
Fetches the current ingredients from the default wger instance
6664
"""
67-
sync_ingredients(logger.info)
65+
sync_ingredients(
66+
logger.info,
67+
show_progress_bar=False
68+
)
6869

6970

7071
@app.task

0 commit comments

Comments
 (0)