My first architecting

Hi everyone,

I’ve been working on a django project for a few years with twin goals of:

  1. developing a useful site with tools for our workshops and seminars,
  2. 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:

  1. 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.

  2. 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.)

  3. 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’

  4. 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.

  5. 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.

Andrew

Just some general comments here - take them all with a bucket of salt.

1 - “Row level security” is a gnarly problem. It’s so specialized and domain-specific that I personally don’t believe that any generic package can do any more than provide the most basic framework. I’ve only talked with a small handful of people that have ever implemented a truly dynamic row-level security model, and they’ve all rolled their own. (Which is what we’ve done.) So I guess what I’m getting at is that whatever works, works…

3 - Can you provide an example or two of what you mean here? Are you just looking to map a more user-recognizable name (slug?) to a URL or are you looking for something else?

5 - Deployments are another gnarly problem. I’ve never heard of anyone’s first deployment going smoothly. (I know mine didn’t.) There’s so much that is situational and environmentally specific that may need to be addressed to make it the most confusing of Django issues. (And I’m fairly certain that I’m not the only person with this opinion.)

Ken

Cheers Ken - thanks for that.
re 3. Basically the Task model has a field for app_label and a method in the ‘get_url’ family that composes a url using reverse(namespace_string, *args) where namespace string is “project:task:”+task.app_label+":index". I’d like to extend it so as to replace the “:index” string with the URLpattern’s attribute “name” (the name=“name” value). I worked out how to get all the names, but will need to do some work to structure the list. We might have an app which helps groups do prioritization, discuss criteria, develop options - we want to assign the start of the task to a specific view of the data, not just a generic landing page.

Ok, I think I’m getting the idea.

Are you aware that the name attribute of a URL does not need to be unique? You can have multiple entries using the same name - and it’s the last one encountered in the list that applies. (No idea whether or not this is at all relevant to what you’re doing, but I thought you ought to at least be aware of it.)

Ken

1 Like