Tuesday, October 24, 2017

Re: Adding several user models



On Oct 24, 2017 3:46 AM, "Andréas Kühne" <andreas.kuhne@hypercode.se> wrote:
Hi all,

I would love to pick your collective brains for a second. I am working on an application that will be first and foremost an administration system. As such there will be very few users in the system. It will have a front end developed in angular 5 and a Django rest framework backend.

I have got the solution up and running currently and it works as I think it should. However - now I have another idea that I would like to hear your opinions on.

Connected to this system we will also have other portals where a user will be able to login - NOT the same user as the user that logs onto the administration system - but an entirely different concept (a participant). These portals will probably be running on another machine (but not necessarily) and can have their own user concept. This application will also be more of a traditional Django project with a standard view and template driven design.

I am thinking about creating the Participant model separate from the User (they are different concepts) and therefore was wondering if it would be possible to create the Participant model based on an AbstractUser from django contrib auth and then in the portal project use that as the user model?

Short answer is yes, with caveats, but it may not be recommended.

The long answer: There's no technical reason that a model defined in one project cannot serve as a reference for another project. The common code just needs to be accessible from both projects. This works the same way as any other Python library, because after all, Django models are just Python code.

There are logical and design issues with doing it, though. A change in the Admin project for the abstract user model will now propagate to the Participant project, possibly in a negative way. You'll need to execute tests for both your Admin and Participant projects whenever changes are made to that model. Adding new features is usually easy, but deprecating code can be a nightmare, as you now have two code bases that need to be analyzed rather than one. You've also directly coupled the two projects together from a semantic versioning standpoint. Even with no changes to the Participant project, a change to the abstract model in the Admin project now forces a migration for the Participant project (if a field is modified), and likely a version bump for the Participant project so that those running your software pick up the changes, even though there were no modifications made to the Participant project itself. 

I'd ask how important it is that these two models be coupled in such a way? Granted, adding common fields between the two is handy, but for the reasons above, it can be dangerous. It's likely that the Admin project only needs a very small subset of the fields that the Participant project needs, and the Admin app has no use for any of the authentication/authorization backend functionality that gets dragged along with AbstractUser. 

Has anyone every done anything similar? Is this idea completely wrong? Any other things that I should think about?

Yes, in the sense that developing a 3rd party app for both projects is effectively what you are doing. These are the same issues faced by 3rd party app developers for Django, where a 1-line change in a 3rd party module requires a migration for anyone that is using the app. 

It's not necessarily wrong, there are just a number of issues to consider with the coupling between the projects that you'll be creating. 


My main reason behind this idea is that the applications will share the database, but be completely different projects and shouldn't necessarily share a web app? Is this also a wrong idea or does this sound sane?


When you say 'share the database', are you referring to the same database server but separate database instances? Or are you expecting both projects to access the same tables in the same database instance? 


All of those issues aside, I wouldn't start with an abstract model inheriting from AbstractUser. I would create a clean abstract model inheriting from models.Model, and copy everything from AbstractUser over to your new abstract user model. Your Admin project would then define a concrete user model that inherits directly from your new abstract user model. Over in the Participant project, your concrete model would inherit from the abstract model created in the Admin project, and also from AbstractBaseUser and the PermissionsMixin, just like AbstractUser does. This way, you have a single model controlling what fields are made available in both applications, but only the Participant project model contains the extra machinery to use that model to authenticate/authorize users. The copy/paste operation probably violates DRY for some purists, but you'll likely be modifying those fields at some point anyway, so I consider it a necessary evil. 

IMO, the number of fields that actually need to be shared between the projects is quite small (less than a dozen), and likely will not change often (hopefully), so the headache of having both coupled to the same abstract class is not worth it for me. Having a note in each user model reminding me to update the other would likely be sufficient, so I wouldn't recommend doing this unless you plan on the base abstract model changing dramatically over time where sync between the two projects may be problematic.

I'm surprised that Django does not break out the AbstractUser fields like username, etc. into a separate abstract model that does not inherit all of the authentication backend functionality, as it forces a code copy for situations like this. Maybe I should do a PR at some point, since that wouldn't break any existing functionality. 

-James

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/CA%2Be%2BciV9-mXKtrtGb4WXEsis%3D7ccsHmsivoBiLz80472RaZhyg%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

No comments:

Post a Comment