Fields inherited from Django's `AbstractBaseUser` / `PermissionsMixin` / `AbstractUser` are missing
Nobody has claimed this yet.
Assessment
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Newbie friendliness
- 62/100
Research direction
Start in cli/orm_lens/parser.py: _abstract_bases_fields() near line 833 skips AbstractBaseUser because by_name.get(tail, []) finds nothing, and _attach_inherited_fields() near line 874 fills inherited_fields from that. Add a table of Django's own abstract bases (AbstractBaseUser, PermissionsMixin, AbstractUser) used only when no workspace class has that name. Done when the repro's drift reports nothing, describe lists the inherited fields, and the new tests plus the golden snapshot update pass with pytest, ruff and mypy.
Written by the indexing model from the issue text.
Description
Source: taiga-back — taiga/users/models.py:117; pretix — base.User; label-studio — users.User; weblate — weblate/auth/models.py:942
What happens
A custom user model usually inherits its auth fields from Django:
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
password and last_login come from AbstractBaseUser, is_superuser, groups and user_permissions from PermissionsMixin. orm-lens only merges fields from abstract bases it can read in the workspace, and those two live in Django itself, so the fields are dropped. The same goes for AbstractUser (username, first_name, email, is_staff, date_joined, ...).
On all four projects above drift reports "migrated but no longer declared: groups, is_superuser, last_login, password, user_permissions", and the M2M edges to auth.Group / auth.Permission are missing from er and cascade.
Repro
accounts/models.py
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
from django.db import models
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
USERNAME_FIELD = "email"
accounts/migrations/0001_initial.py (what makemigrations writes for it)
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [("auth", "0012_alter_user_first_name_max_length")]
operations = [
migrations.CreateModel(
name="User",
fields=[
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
("password", models.CharField(max_length=128, verbose_name="password")),
("last_login", models.DateTimeField(blank=True, null=True, verbose_name="last login")),
("is_superuser", models.BooleanField(default=False)),
("email", models.EmailField(max_length=254, unique=True)),
("groups", models.ManyToManyField(blank=True, related_name="user_set", related_query_name="user", to="auth.group")),
("user_permissions", models.ManyToManyField(blank=True, related_name="user_set", related_query_name="user", to="auth.permission")),
],
),
]
$ orm-lens drift
~ accounts.user:
migrated but no longer declared: groups, is_superuser, last_login, password, user_permissions
summary: 1 model(s) drifted, 0 blocking, 1 migration(s) replayed
$ orm-lens describe accounts.User
| Field | Type | Args |
| --- | --- | --- |
| `email` | EmailField | `unique=True` |
With class User(AbstractUser) plus one own field, describe likewise shows only that field.
Expected: no drift; describe lists the inherited fields too, and groups / user_permissions are M2M relations to auth.Group / auth.Permission.
Where
cli/orm_lens/parser.py
- line 833,
_abstract_bases_fields():by_name.get(tail, [])finds nothing forAbstractBaseUser, so the base is skipped; - line 874,
_attach_inherited_fields(): fillsinherited_fieldsfrom that.
Suggested fix
Add a small table of Django's own abstract bases and their fields (as ParsedField, with inherited_from set):
AbstractBaseUser:password(CharField,max_length=128),last_login(DateTimeField,blank=True, null=True);PermissionsMixin:is_superuser(BooleanField),groups(ManyToManyField →auth.Group),user_permissions(ManyToManyField →auth.Permission);AbstractUser: both of the above plususername,first_name,last_name,email,is_staff,is_active,date_joined.
In _abstract_bases_fields(), when by_name has no class for the base name and the name is in the table, use the table's fields. A class with the same name in the workspace still wins, so a project that defines its own PermissionsMixin isn't affected. Note that is_active on AbstractBaseUser is a plain class attribute, not a field.
How to test
- A new test with the repro:
driftreports nothing,describelistspassword,last_login,is_superuser,groups,user_permissions,email. class User(AbstractUser)gets theAbstractUserfields; an ownemailshadows the inherited one.- A workspace class named
PermissionsMixin(abstract, with its own fields) is used instead of the table. - Run the golden snapshots: zulip's
UserProfileusesAbstractBaseUserandPermissionsMixin, so it will gain fields. Update the snapshot and list the changes in the PR. cd cli && python -m pytest -q,ruffandmypypass.
Difficulty: good first issue, a lookup table and one branch.
- Dominant language
- Python
- Stars
- 84
- Forks
- 13
- PR merge metrics
- No merged PRs in 30d
Getting set up
- Ships a Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from FROWNINGdev/django-orm-lens
-
suggest-indexes proposes composite indexes that include the primary key or a unique fieldPossibly taken @bfs2021 claimed this today. Openbug good first issue python
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
FROWNINGdev/django-orm-lens#269 ·
-
`migration-risk` text output prints `app.None` for graph-level findingsPossibly taken @phoenixbycaselka claimed this today. Openbug good first issue python
Difficulty 1/5 1-3 hours Newbie friendliness 88/100
FROWNINGdev/django-orm-lens#268 ·
-
Finish the Chinese rule reference — DOL001–DOL007May be free again @harbinresearcher claimed this 64 days ago, and no pull request is open. Opendocumentation good first issue help wanted
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
FROWNINGdev/django-orm-lens#81 · 2 comments ·
-
bug good first issue python
Difficulty 3/5 Half a day Newbie friendliness 78/100
FROWNINGdev/django-orm-lens#266 ·
-
enhancement help wanted python
Difficulty 4/5 3-5 days Newbie friendliness 35/100
FROWNINGdev/django-orm-lens#254 ·
All issues in FROWNINGdev/django-orm-lens
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
roman-corgi/corgisim#327 ·
Maintainers usually reply within 2 days
-
[Bug]: opencode_go chat route drops reasoning_effort (even 'none'), while the same endpoint honors it via custom_llm_provider=openaiPossibly taken @arvindkumar-ship-it claimed this today. Openllm translation
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
BerriAI/litellm#51871 · 1 comment ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Maintainers usually reply within 1 day
-
PolicyEngine backdates South Carolina’s EITC into 2015–2017Possibly taken @MaxGhenis claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
PolicyEngine/policyengine-us#10944 ·
Maintainers usually reply within 2 days
-
fix(frontend): resolve SSE parser crash on unhandled Ref methods and undefined actions identifierOpenbug
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
kodokbakar/MiroFish-Local#94 ·
Maintainers usually reply within 1 day