Skip to content

Conversation

@adam-knights
Copy link
Contributor

@adam-knights adam-knights commented Feb 10, 2026

Following on from #696 we also implement the group origin universe pages in the same way. Code reuse and my styling should be much more in keeping first time this time :). Tested lots locally with normal group, origin with group and group with universe attached.

image

There was also an existing bug where active_generalisations was not working on groups, the relation id was using 6 like characters, but it needs to be 5 on groups. This probably means its not used much / we don't have many bottom level groups, but good to have it working consistently like characters in any case, so all the views now use active_generalisations too to support both ways to view. As an example if you goto https://www.comics.org/group/4/, fourth from the bottom there should be a link to the bottom level group for MC2 but its not displayed, and then with the fix locally:

image

There was also a couple heading texts I'd got wrong on the character implementation where 'with origin' appeared before the wrong %s, those are fixed too.

I noticed a random 'external links' in the middle of the group page, i think not intentional, so removed it, but can adjust if needed:

image

Finally, because all the code is now there, i added the 'Groups from this universe' link to the universe page and supporting table etc:

image image

@gemini-code-assist
Copy link

Summary of Changes

Hello @adam-knights, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the platform's data browsing capabilities by introducing dedicated overview pages for 'Group Origin Universe', building upon similar functionality previously implemented for characters. It addresses a critical bug in group relation filtering, ensuring that group generalisations are correctly identified and displayed. The changes integrate universe-specific filtering into numerous existing views and tables, providing a more consistent and detailed user experience when exploring groups within the context of their originating universes. Additionally, minor UI improvements and navigation links have been added to improve overall usability and consistency.

Highlights

  • Group Origin Universe Pages: Implemented dedicated overview pages for 'Group Origin Universe', providing a structured way to view groups within the context of their originating universes, mirroring existing character functionality.
  • Bug Fix: Group Generalisations: Corrected a bug where active_generalisations for groups incorrectly used relation_type_id=6 instead of 5, ensuring consistent and accurate filtering of group relations.
  • Extended Universe Filtering: Extended filtering and display logic across various views and tables (e.g., creators, features, series, issues, covers, sequences) to support the new group origin universe context, enhancing data exploration.
  • New Table for Universe Groups: Introduced a new UniverseGroupTable specifically designed for presenting groups within a universe context, improving data presentation.
  • UI/UX Improvements: Refined heading text formatting in several character-related views, removed an unintended 'external links' heading from the main group detail page, and added a 'Groups from this universe' link to the universe detail page for better navigation.
Changelog
  • apps/gcd/models/character.py
    • Fixed active_specifications and active_generalisations to use relation_type_id=5 for groups.
    • Modified active_universe_appearances to handle group generalisations and added active_universe_appearances_with_origin for specific universe filtering.
    • Added UniverseGroupTable for displaying groups in a universe context.
  • apps/gcd/models/creator.py
    • Updated render_issue_count in creator tables to support group origin universe URLs.
  • apps/gcd/models/feature.py
    • Modified feature issue count rendering to include group origin universe context and added universe ID to table initialization.
  • apps/gcd/models/series.py
    • Updated series appearance count rendering to include group origin universe context and added universe ID to table initialization.
  • apps/gcd/urls.py
    • Added new URL path for universe_groups.
    • Removed deprecated group_issues_per_universe URL.
    • Introduced a comprehensive set of new URL patterns for group origin universe pages and their filtered sub-pages (creators, issues, covers, series, features, sequences, group names).
  • apps/gcd/views/details.py
    • Imported UniverseGroupTable.
    • Implemented _resolve_group_universe helper for consistent group and universe resolution.
    • Modified checklist_by_id and creator_name_checklist to use the new group universe resolution logic.
    • Added universe_groups view to list groups within a universe.
    • Corrected heading text formatting in character_issues_character, character_issues_feature, and character_issues_series.
    • Added group_origin_universe view for the new overview page.
    • Updated group_features, group_issues, group_name_issues, group_issues_feature, group_issues_series, group_series, group_creators, group_sequences, and group_covers views to incorporate group origin universe filtering and dynamic heading generation.
  • templates/gcd/details/tw_group.html
    • Removed a redundant 'external links' text.
    • Updated the 'Appearances With a Group Origin Universe' section heading and links to point to the new group_origin_universe page.
  • templates/gcd/details/tw_group_origin_universe.html
    • Added a new template for displaying the Group Origin Universe overview page, including links to various filtered lists and dynamic content.
  • templates/gcd/details/tw_universe.html
    • Added a navigation link to view groups from a specific universe on the universe detail page.
Activity
  • The author, adam-knights, implemented this pull request as a follow-up to a previous PR (Add character origin universe overview page with links to all #696) which introduced similar functionality for characters.
  • Extensive local testing was performed, covering various scenarios including normal groups, origins with groups, and groups with universes attached.
  • A bug was identified and fixed where active_generalisations for groups was not working correctly due to an incorrect relation ID.
  • Several UI inconsistencies, such as incorrect heading texts and a stray 'external links' section, were addressed.
  • New functionality was added to link 'Groups from this universe' from the universe page, improving navigation.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces group origin universe pages, mirroring existing functionality for characters. It also includes several important bug fixes and refactorings, such as correcting a relation ID for group generalizations, fixing incorrect headings, and removing stray UI text. The code is cleaner and more reusable in several places. I've identified a few critical issues related to incorrect super() calls that could lead to bugs, and some potential race conditions with .get() that should be addressed. There are also a couple of minor bugs and opportunities for performance improvement. Overall, a great set of changes that significantly enhance functionality.

self.group = kwargs.pop('group')
self.universe_id = kwargs.pop('universe_id', None)
self.resolve_name = 'group'
super(CharacterFeatureTable, self).__init__(*args, **kwargs)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

This super() call is incorrect. GroupFeatureTable inherits from CharacterFeatureTable, so the super() call should refer to GroupFeatureTable to correctly call the parent's __init__ method. The current implementation will skip CharacterFeatureTable.__init__ and call the __init__ of its parent (FeatureSearchTable), which is likely not the intended behavior and can lead to bugs. The correct Python 3 syntax would be super().__init__(*args, **kwargs).

Suggested change
super(CharacterFeatureTable, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is existing code and i believe intended

self.group = kwargs.pop('group')
self.universe_id = kwargs.pop('universe_id', None)
self.resolve_name = 'group'
super(SeriesTable, self).__init__(*args, **kwargs)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

This super() call is incorrect. GroupSeriesTable inherits from CharacterSeriesTable, but this call skips CharacterSeriesTable.__init__ and its parent's __init__, directly calling a method from SeriesTable's MRO. This is a bug and can cause incorrect initialization. The correct Python 3 syntax would be super().__init__(*args, **kwargs).

Suggested change
super(SeriesTable, self).__init__(*args, **kwargs)
super(CharacterSeriesTable, self).__init__(*args, **kwargs)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is existing code and i believe intended

def active_universe_appearances(self):
from .story import Story
if self.universe and self.active_generalisations().exists():
group = self.active_generalisations().get().from_group

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The use of .get() here is risky as active_generalisations() could potentially return more than one object, which would raise a MultipleObjectsReturned exception. To make the code more robust, consider using .first() and checking if an object was returned. This will prevent unexpected server errors if the data ever allows for multiple generalizations.

Suggested change
group = self.active_generalisations().get().from_group
group = self.active_generalisations().first().from_group

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This matches the character version that already exists.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We want server errors if the data is wrong.

Comment on lines 464 to 467
appearances = Story.objects.filter(
appearing_groups__group_name__group=self,
appearing_groups__deleted=False,
appearing_groups__universe_id=origin_universe,
deleted=False)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This query is missing a filter for appearing_groups__deleted=False. Other similar queries in this file include this filter to exclude deleted story-group relationships. Without it, you might be including data from deleted appearances.

        appearances = Story.objects.filter(
          appearing_groups__group_name__group=self,
          appearing_groups__universe_id=origin_universe,
          appearing_groups__deleted=False,
          deleted=False)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 7497f30

Comment on lines +942 to +943
filter_group = group.active_generalisations().get()\
.from_group

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The use of .get() here is risky as active_generalisations() could potentially return more than one object, which would raise a MultipleObjectsReturned exception. To make the code more robust, consider using .first(). This will prevent unexpected server errors if the data ever allows for multiple generalizations.

Suggested change
filter_group = group.active_generalisations().get()\
.from_group
filter_group = group.active_generalisations().first()\
.from_group

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This matches characters.

break
if not found:
# more a GroupNameDetail.DoesNotExist exception here ?
raise

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Re-raising the MultipleObjectsReturned exception here will result in a 500 server error, which is not user-friendly. The developer comment suggests this might not be the best behavior. Consider handling this case more gracefully by rendering an error page to the user, similar to how other errors are handled in this view (e.g., the "Name does not exist at group generalization" error).

                    return render(request, 'indexer/error.html',
                                  {'error_text':
                                   'Could not find a unique name match for ' 
                                   'the group generalization.'})

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code now matches the character equivalent, we would change together if we want to.

stories = Story.objects.filter(**query).distinct()\
.select_related('issue__series__publisher')

heading = 'Sequences for Group %s' % (group)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The heading variable is calculated with universe context using _build_universe_filter_and_heading earlier in the function, but it's being overwritten here. This causes the universe information to be lost from the page heading. This line should be removed to display the correct heading.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 7497f30

def __init__(self, *args, **kwargs):
self.universe = kwargs.pop('universe')
kwargs['group'] = True
super(UniverseGroupTable, self).__init__(*args, **kwargs)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This super() call uses Python 2 syntax. For consistency with the rest of the codebase and modern Python 3 practices, it's better to use the argument-less super().__init__(*args, **kwargs).

        super().__init__(*args, **kwargs)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This matches the existing UniverseCharacterTable for consistency.

'with group %s',
(group,))

issues = issues.filter(**query)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This query might return duplicate Issue objects if a creator worked on multiple stories within the same issue that match the query. Consider adding .distinct() to the end of the filter to ensure each issue appears only once in the results, similar to how it's handled in other parts of the code (e.g., in checklist_by_id).

Suggested change
issues = issues.filter(**query)
issues = issues.filter(**query).distinct()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 7497f30

Comment on lines 4897 to 4898
if issues:
selected_issue = issues[randint(0, issues.count()-1)]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The issues.count() method is called twice here (once implicitly in the if issues: check, and once inside randint). For a minor performance improvement, you could store the count in a variable.

    issues_count = issues.count()
    if issues_count:
        selected_issue = issues[randint(0, issues_count - 1)]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 7497f30 - also did the same to the origin character equivalent from last time

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think issues,count() is cached, so
if issues.count():
would be fine as well

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants