Opened 16 years ago
Last modified 10 months ago
#12096 new New feature
Model fields are not accessible as attributes of the model class
| Reported by: | sejo | Owned by: | |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | dev |
| Severity: | Normal | Keywords: | model, docstrings, attributes |
| Cc: | Triage Stage: | Accepted | |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
When using attribute docstrings in my models they will never be picked up by doctools as the attributes disappear top level from the model.
This makes me to keep separate documentation and code for djagios.
Change History (13)
comment:1 by , 16 years ago
comment:2 by , 16 years ago
| Owner: | changed from to |
|---|---|
| Status: | new → assigned |
comment:3 by , 16 years ago
| Triage Stage: | Unreviewed → Accepted |
|---|
comment:4 by , 16 years ago
comment:5 by , 15 years ago
| Severity: | → Normal |
|---|---|
| Type: | → Bug |
comment:8 by , 13 years ago
| Component: | Core (Other) → Database layer (models, ORM) |
|---|
comment:9 by , 10 years ago
| Owner: | removed |
|---|---|
| Status: | assigned → new |
| Summary: | model attributes are not set toplevel which causes doctools to miss the attribute docstrings → Model fields are not accessible as attributes of the model class |
| Type: | Bug → New feature |
I'm not sure what the implementation should look like. It seems that Jacob's comment about "ModelClass.field raises AttributeError is obsolete.
comment:10 by , 10 years ago
To get this to work we need to change some low-level stuff since model fields are stripped out by the metaclass to be put in Model._meta. Since Sphinx's autodoc module allows to manually add members to a class I think it would be better to do in manually than trying to change the way Django models are constructed.
Anyway, I came up with the following code that makes Sphinx's autodoc work for Django models. It is very hackish and unsurprisingly makes some tests fail, so I'm just putting this here for the record in case anyone would want to take that over someday.
class ModelBase(type): def __getattr__(self, attr): if attr == '_meta': raise AttributeError(attr) try: return self._meta.get_field(attr) except FieldDoesNotExist: raise AttributeError(attr) @property def __dict__(self): try: model_dict = { f.name: f for f in self._meta.get_fields() } except AppRegistryNotReady: model_dict = {} model_dict.update(super(ModelBase, self).__dict__) return model_dict # Rest of ModelBase code...
comment:11 by , 3 years ago
Since DeferredAttribute are systematically added as model class attributes (#26207) this would be a simple matter of adjusting a few __get__(instance=None) case to return self.field (DeferredAttribute and the three classes of related_descriptors).
The only remaining concern here is backward compatibility. The only documented pattern of accessing a field attribute from the class is for ManyToMany.through via ManyToManyDescriptor.through but there might be valid use cases in the wild for expecting descriptors to be returned that this change could break. As long as we document this change and that it's still possible to retrieve descriptors by doing ModelClass.__dict__.get('descriptor') I think we should be fine though.
Beyond the documentation benefits this could pave the way for interesting features that the verbosity of Model._meta.get_field such as SQLAlchemy-esque lookups (e.g. Book.objects.filter(Book.title.contains(Book.author.name)) ) but most importantly it would restore the most intuitive pattern for field retrieval.
comment:12 by , 14 months ago
| Owner: | set to |
|---|---|
| Status: | new → assigned |
| Version: | 1.1 → dev |
comment:13 by , 10 months ago
| Owner: | removed |
|---|---|
| Status: | assigned → new |
This is actually because
ModelClass.fieldraisesAttributeErrorfrom the descriptor. I've been wanting to stop that, anyway -- it ought to just return theFieldobject.