I’ve been working on a django project for a few years with twin goals of:
- developing a useful site with tools for our workshops and seminars,
- developing the skills to compose good tools as needed.
Our workshops are often unique (the questions, process, activities etc are new), but the people conducting them are the same, so we have that tendency to want to reuse things that worked last time with slight modifications. We’re using Django to collect and organise user input, mediate the sharing of content participants are generating, that sort of thing. So the models, forms, etc get a workout in some places, but we also need to customise the user experience for more detailed steps.
In the last six or nine months, my solo project has suddenly picked up steam and new workers and diverse new requirements. So, as the person who has been learning Django the longest (about two years, maybe three, but little or no previous programming experience) I am trying to develop guidelines for new apps that are intended to be enrolled in the site.
So, some choices - treat these as requests for advice, or cries for help:
I need users to only see information and questions that concern them. I’ve done this using ‘target_groups,’ a ManyToManyField to Group from the ‘auth’ app to important content objects. I wrote an app called ‘projects’ that provides models for Project and Task (with a Project fk), each of which have a ‘target_groups’ field. A custom DiscreetManager gets the request.user and filters returns from get and get_queryset to check the user is in the relevant groups. This seemed to be the minimal approach, but the projects app is like a middleware to the other apps. I looked at django-guardian a little too late, but it also seemed more heavy-duty than we require.
This approach created the following simple but numerous changes to enroll an app into the site - to incorporate a ‘polls’ app, I have to modify the source from the standalone version - the models all need to use a DiscreetManager that knows how to find out what project/task (and hence target_group) each object in a table belongs to. The views in the app all need to tolerate extra kwargs because they’ve been include() in a project:task namespace stack. The links in the templates all need to be modified to know about the top namespaces. As long as the current ‘one team working one way on one site’ continues, its acceptable, but limiting reusability of apps is a serious thing to trade away. Also an issue for tests (discussed in 4.)
Currently a Task is performed in an app, and each app must define a path named ‘index’ as the landing page when your group attempts that task. I’ve had a request to support landing on any of an apps paths either by name or url. I could use a URLField, but it might require manual updating of data in the fields when the site is updated. I could store viewname as a CharField, but I would like the ‘choices’ property to be appropriate to the app_label. I don’t know how to get a list of viewnames from an apps ‘urls.py’
Testing. I wrote tests for my first app, but got discouraged at how many lines of code it took, so I wrote a single test that would to generate urls for every url in my first app, trying to minimise the lines of code to be maintained because the site is growing organically as needed, not to a pre-existing specification. But I haven’t written any tests until recently. I dislike and do not believe in the sort of tests that are created for tutorials, where in 5-10 lines of code you define one test of whether the page loaded or the expected template was used. If all the standalone apps came with tests, all the tests would need to be amended when they’re integrated with the site. What I am working on is a test set that SetsUp objects in the database, tests that they’re there, then tests a viable example of each possible URL by substituting relevant object_id values. [In an ideal world, I’d have a factory that generates testcase functions and adds them to the instance. test_[url]get() and test[url]_post() for all the urls. Not sure how to do that.] I would like a single test script that can be used by all developers to test the common functions of any app - with little or no app-specific content.
Deploying has been one of the more difficult processes. The database configuration is relatively trivial compared to the upstream setup of nginx and gunicorn / uwsgi or setting up for docker. We got to a basic setup, but took a long time and I’m not satisfied I really know how it works / am using them correctly.