How to describe parameters in DRF Docs - python

I'm using Django REST Framework v3.6 built-in interactive documentation django_rest_framework.documentation (not django-rest-swagger).
Basically, I'm following the official documentation and use this in my URLset configuration:
from rest_framework.documentation import include_docs_urls
urlpatterns = [
url(r"^", include_docs_urls(title="My API")),
...
]
Everything seems to work and I get a nice interactive documentation page, but I have a ViewSet with lookup_field = "slug" and one thing about the generated documentation bothers me:
I want to have some useful information it that description, like "an unique permanently-assigned alphanumeric ID" or something among those lines, but can't find any documentation where this data comes from.
There is a workaround but I really don't want to define all the schema explicitly. I want to declare my classes with nice docstrings and have docs auto-generated. I've also found an suggestion to put slug -- here goes the description in the docstring but it doesn't seem work - the text just appears with the rest of the Markdown-formatted description.
So... I wonder about two things:
(A specific question) Where do I fill this path parameter description?
(More generic version of the same question) What's the best way to learn how schemas are auto-generated from code?

Oh, I found it. Answering my own question.
DRF documentation isn't verbose on this matter (or I've missed the piece where it is), but it mentions rest_framework.schemas.SchemaGenerator class and it seems that this class really does all the introspection stuff. Fortunately, the source code is well-structured and easy to read.
Those path fields are generated by get_path_fields method (I found it by tracing the execution path: get_schema → get_links → get_link), and I found that descriptions come from model fields's help_text attribute.
So in my model I've specified:
class MyResource(models.Model):
slug = models.CharField(unique=True, help_text=_("unique alphanumeric identifier"))
...
And it worked!

One important thing was not still covered. It is true that a description comes from the help_text attribute, but this is not enough. I have found that the schema generator rely on view's queryset attribute to determine a model. So, keep in mind that you need define it even if you don't need it. For example in case of using APIView.

Related

Does django-rest-swagger not work well with modelserializers?

I've been going off of the documentation on the django-rest-swagger github page, more specifically the part called "How it works". It shows that you can define your own parameters for your rest api, and have those parameters show up in your swagger doc page.
The commenting example is something like:
"""
This text is the description for this API
param1 -- A first parameter
param2 -- A second parameter
"""
I can get this to work, but my issue is how to specify if the variable is required, its parameter type, and its data type. The github page shows an example image of how your swagger doc could look, and they have the information I just mentioned. But when I comment my custom parameters like the example shows, my parameters just show as parameter type: "query", data type: is blank, and it doesn't show "required".
The closest thing I have found to an answer was in this stackoverflow question. It seems like an answer provider is saying that django-rest-swagger generates its documentation by automatically inspecting your serializers (which is fine), and that modelserializers won't contain enough information for django-rest-swagger to properly derive the criteria I mentioned above. I get that it can't figure out this criteria but there must be some way for me to manually specify it then.
Am I correct that django-rest-swagger would only display what I want if I rewrote my modelserializers as just serializers? Is there no way for me to manually tell django-rest-swagger what a parameter's parameter type and data type should be, and if it's required?
I know I must be missing something here. I use class-based views and modelserializers that are almost identical to the examples in the django-rest-framework tutorials. It seems entirely possible that I'm just missing an understanding of "parameter types" in this context. My API is working great and I don't want to rewrite my modelserializers to serializers just so I can get better automatic documentation through swagger.
ModelSerializers are the right way to go with DR-Swagger. It can be a bit tricky chasing down exactly where the different Swagger fields are extracted from though, I often had to fall back to step-debugging through the page rendering process in order to figure out where things were coming from.
In turn:
Required? comes from the Field.required parameter (either set on the model or the Serializer field).
Description comes from the Field.help_text parameter.
In the new-style DRF serialization, the description text comes from the ViewSet's docstring. If you want method-specific docs, you need to override the docstring for individual methods, e.g. retrieve:
def retrieve(self, request, *args, **kwargs):
"""Retrieve a FooBar"""
return super().retrieve(request, *args, **kwargs)
One thing to note is that DR-Swagger migrated to using the new DRF schema logic in version 2.0 (with DRF version 3.5), which has a few rough edges still. I recommend sticking with DR-Swagger version 0.3.x, which (though deprecated) has more features and in my experience, more reliable serialization.
In most cases ModelSerializer is what you need, because it can be greatly customized to suit your needs. In ideal situation you should define all your constraints, like required attribute on a field, in your model class, but there are times when it's not architecturally possible, then you can override such a field in your ModelSerializer subclass:
from django.contrib.auth import get_user_model
from rest_framework import serializers
class UserSerializer(serializers.ModelSerializer):
first_name = serializers.CharField(required=True)
last_name = serializers.CharField(required=True)
class Meta:
model = get_user_model()
In the example above I serialize standard User model from Django and override required attributes so, that first_name and last_name are now required.
Of course, there are cases when it's hard or impossible to use ModelSerializer then you can always fallback to Serializer subclassing
In the code you have:
"""
This text is the description for this API
param1 -- A first parameter
param2 -- A second parameter
"""
Try:
""" This text is the description for this API
param1 -- A first parameter
param2 -- A second parameter
"""
I have found some python and/or Django plugins need the docstring's first line, which is the one with the opening three double-quotes to also be the line that starts the documentation. You might even want to try no space between the last double-quote and the T.

Trac - How do I access Custom Ticket Fields in ITicketChangeListener?

I'm trying to write my own Trac plugin to notify an external system of changes to tickets matching a certain criteria. From my research so far, I've figured out that implementing the ITicketChangeListener interface is the way to go.
The method definitions are all very straight forward, but what's not straight forward for me is the Ticket object and accessing its custom fields. I've learned that you can access default ticket fields as simply as:
# t is a Ticket object
theStatus = t['status']
I've found several sources that say this won't work:
myCustomField = t['my_custom_field']
Yet none of them tell me what will work.
In addition, I need to know if the old_values argument of the ticket_changed() method will have my custom fields or if I'll have to do something different there as well.
I'm fairly new to Python and very new to Trac. Any help to point me in the right direction is appreciated.
The sources are wrong about custom ticket fields. The value-by-name approach should work. And *old_values* contains all fields values, including custom fields too. That's it.
You may want to look at the TracAnnouncer source for some change-listener coding examples.

Is it safe to access ._meta directly in your django app?

Django uses Meta class for lots of additional object information. However, they store this information in an object '_meta' which by naming convention is private.
All over the django admin (and other places) I see stuff like opts = model._meta and then they use the various options like app_label and verbose_name.
Can I be confident accessing ._meta and be sure that it will not change in the future, or am I better off creating one 'accessor' mixin or something that accesses the ._meta in one spot, so if it ever does change I only have to update one thing?
I use _meta frequently and haven't had any issues so far. You can see in the django documentation an example of them using it too here, so I have felt its more or less ok to do. Just tread carefully and write good tests so you know of any problems when you upgrade your django version later on down the road.
I use _meta in several projects where I want to have generic access to information that's otherwise not provided by the api. I think you're probably okay most of the time as Django is pretty stable. It's probably a good idea to be covering your usage of _meta in your unit tests.

Reverse ForeignKey lookup

I'm new to Django and am still trying to break old PHP habits. Below are two models. To make things confusing they live in separate files, in different apps...
#article.models
from someapp.author.models import Author
class Article(model.Model):
...
author = models.ForeignKey(Author)
# author.models
class Author(model.Model):
...
From this schema I want to be able to get all the articles by an author. Something like:
author = Author(pk=1)
articles = author.articles
My first reaction was to write a method that did a simple look up in the article model based on the authors ID. What happened here was a never ending inclusion loop because of the separate files. Article needed Author imported to use for the ForeignKey and Author needed article included to use for the model look up. This felt hacky and wrong. I would much rather do it the right way... So, what is the Django way?
I think this is what you're asking for...
class Article(model.Model):
...
author = models.ForeignKey(Author, related_name='articles')
On a side note, by default without changing anything you've got, I think this would work for you...
article.author_set
But to maintain the article.authors syntax you mention above, you can specify that yourself with related_name.

Using classes for Django views, is it Pythonic?

I'm currently learning Python and coming from a strong C# background. I keep hearing about doing things in a Pythonic way to take advantage of the dynamic nature of the language and some of it I get and some I don't.
I'm creating a site with Django and my approach to views is to use classes. My current thinking is to have a base class that has some stuff about the template and the model to use. This will have a default funky 404 type page with site search and stuff on then base all the other pages off this. So each area of the site will have its own EG News and all the model related functions and filtering will be in that class with a further class on top of that for HTML or AJAX requests. So you would have something like this:
\site\common\ViewBase
--\news\NewsBase(ViewBase)
--\news\HtmlView(NewsBase)
--\news\AJAXView(NewsBase)
URLs would be mapped like http://tld/news/latest maps to site.news.htmlview and http://tld/news//to/ will be also be mapped site.news.htmlview but the class will figure out what to do with the extra params.
This is pretty much what I would do in C# but the Django tutorial only shows using methods for views, making me wonder if this is not a very pythonic solution?
Thoughts?
Edit: After S.Lott comment about thread safety, Is it better to leave the functions as they are and have them create an instance of a class and call a method on it?
What I am looking for is a place to put common code for each section of the site for filtering the model, authentication for the site, etc
Certainly there's nothing wrong with using a class for a view, provided you route the URL to an actual instance of a class and not just a class directly.
The Django admin does exactly this - look at the source code in django/contrib/admin.
The advantage of classes is that they are much easier to customize, for example you can add hooks for permission checking.
There is a proposal to move all existing generic views over to classes, it was supposed to get into 1.2 but failed to meet the deadline.
As the above poster points out, be very careful about handling instance variables - if you look at the admin classes, you see the request being passed to the various methods instead of relying on "self".
Setting aside other concerns (such as thread-safety issues), it feels like there's a real possible danger here to cross the bright lines between Model / View / Template.
Or maybe it feels like a replacement for url dispatching (not that there's anything wrong with that :-). I'm not sure, but it just feels slightly off.
While class-based views are useful, inheritance may not be the right tool for this particular job. Helper functions and decorators are two great ways to factor out common code from your views. They also tend to be be more familiar/natural to other (python) coders who might work on your code.
I'm not sure what the best approach is in your case as I don't know how much you ultimately want to factor, just keep in mind that there are other ways to factor in python besides inheritance.
p.s. kudos for seeking out a pythonic solution.

Categories

Resources