181 featprofile add complete user profile display with demographic data#190
Merged
NorbertAguilera merged 13 commits intoJun 11, 2026
Conversation
… in admin porfile
…play-with-demographic-data
…play-with-demographic-data
NorbertAguilera
approved these changes
Jun 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR: Add demographic fields and views analytics dashboards
Summary
Added demographic profile fields (gender, age range, municipality) to user registration and profile editing, along with 5 analytics dashboards for Admin/Staff users with Chart.js. Also includes a province→municipality two-dropdown selector linked via JS with data for all Spanish provinces and municipalities.
Changes made
Models (
web_app/models.py)ine_code(2 chars, unique) andnameine_code(5 chars, unique),name, FK to Provincegender(CharField),age_range(CharField),municipality(FK to Municipality)Forms (
web_app/forms.py)gender,age_range,province,municipalityfields with validation ensuring the municipality belongs to the selected province.save()persists all three new fields.provincefield (ModelChoiceField).__init__pre-selects the user's current province. Same validation as registration.Admin (
web_app/admin.py)ProvinceAdminandMunicipalityAdminwith list display and filtersURLs
web_app/urls.py: New routeapi/municipalities/<int:province_id>/for AJAX municipality loadingusers/urls.py: 5 new routes for demographic dashboards underadmin/dashboard/demographics/API (
web_app/views.py)municipalities_by_province: View returning JSON with municipalities for a given provinceProfile views (
users/views.py)user_profile: Now passesprovinces,current_province_id, andcurrent_municipality_idto the template contextAnalytics services (
users/services.py)_base_view_filters: Reusable filters for date and platformget_views_by_gender: Views grouped by genderget_views_by_age_range: Views grouped by age rangeget_views_by_province: Top 10 provinces + "Others"get_views_by_gender_age: Gender × age cross-tabulation (for grouped bar chart)Dashboard views (
users/views.py)admin_dashboard_demographics: Overview with 4 mini-charts (doughnut, bar, horizontal bar, grouped bar)admin_dashboard_views_by_gender: Doughnut chart + data tableadmin_dashboard_views_by_age: Bar chart + data tableadmin_dashboard_views_by_province: Horizontal bar chart (Top 10 + Others) + data tableadmin_dashboard_cross_tab: Grouped bar chart (Gender on X-axis, colored by Age Range) + data tableAll dashboard views use
@user_passes_test(is_admin_or_staff)(Admin/Staff only).Middleware (
users/middleware.py)Templates
register.html: 4 new<select>elements (gender, age_range, province, municipality) with JS that fetches municipalities on province changeuser_profile.html: Same, with current province/municipality pre-selected and initial load via JSuser_client.html: 3 new glass-cards in the sidebar (Gender, Age range, Location)user_admin.html: New "Demographics" tab in the navigation menudashboard_demographics.html: Overview with 4 charts and sub-navigation pillsdashboard_views_by_gender.html: Doughnut Chart.js + data tabledashboard_views_by_age.html: Bar Chart.js + data tabledashboard_views_by_province.html: Horizontal Bar Chart.js + data tabledashboard_cross_tab.html: Grouped Bar Chart.js (Gender × Age) + data tableCSS
register.css: Styles for.form-group select(dark theme, custom arrow, disabled state)user_profile.css: Styles forselect.form-control(custom arrow, dark background for options)Data (
data/municipalities_spain.json)Management command (
web_app/management/commands/load_municipalities.py)python manage.py load_municipalities: Reads the JSON and runsupdate_or_createfor provinces and municipalities. Accepts optional--sourcefor an alternate file path.Known bug (not fixed in this PR)
Infinite 302 loop for non-superuser Staff Admin:
AdminRedirectMiddlewareredirects alltype == 'Staff Admin'users tostaff_admin_panel, but thestaff_admin_panelview (and all other staff views) have@user_passes_test(lambda u: u.is_superuser). When a non-superuser Staff Admin tries to access any page, the middleware redirects them to the panel, the decorator redirects them to login, the middleware catches it → infinite loop.Pending fix: Add
'login'to the Staff Admin exempt list in the middleware, or change the decorators totype == 'Staff Admin'.Run after merge
python manage.py makemigrations && python manage.py migrate python manage.py load_municipalities