Custom User with Parent Model

Hi All,

I’m very new to Django so apologies in advance if this is an obvious problem, I have been through docs and numerous blog posts etc. but not getting anywhere fast so hoping someone can help here. I feel like my requirement is relatively straight forward so hopefully I’m just missing something obvious. This is a bit long winded too, trying to give as much info as possible, so again, apologies.

I was hoping to be able to create a “model” which acts as a parent to the User model, for example, each User is a member of a department. The available Departments are stored in a separate Department model. The Department ID will be part of the User model and have an FK relationship to the Department model, manyToOne - since a Department can have many users, essentially a parent table to User. I want to ensure users cannot be created unless a pre-existing Department is selected.

I also have the requirement to use Email address as the Username. So to this end, I have created a custom user model as per the docs: https://docs.djangoproject.com/en/dev/topics/auth/customizing/#extending-user

The custom model is all working fine, I can add a user with email address as the username and some other simple extra attributes like phone number, so I know that is OK.

I then tried to implement my Department bit, so I have defined a simple model like this;

class Department(models.Model):
department_name = models.CharField(max_length=150, unique=True)

Then in my custom User model I have the below additional field defined:

department = models.ForeignKey(Department, on_delete=models.PROTECT)

This all hung together OK when making migrations and I can see the FK relationship in my DB:

In my custom user creation form I have a ChoiceField which fetches the data from Departments to provide the available options, all good so far.

Now for the issue, when I try to submit the data for a new user it fails with:

Cannot assign “‘1’”: “User.department” must be a “Department” instance.

Inside the “create_user” function of my custom User model I have added this to fetch the company instance based on the passed in ID from the form, but it hasn’t helped;

company = Company.objects.get(pk=company_id)
user = self.model(
email=self.normalize_email(email),
first_name=first_name,
last_name=last_name,
contact_number=contact_number,
company_id=company
)

Am I trying to do something fundamentally bad / impossible here? Or have a I just missed some steps? I’ve googled a lot and cannot find any examples of what I am trying to achieve.

Versions;
Django: 3.0.3
Python: 3.7.6

If any other info would be useful please let me know or if I have misplaced this question let me know where I should be asking.

Thanks,

Hi Paul. It sounds as if you need to be using ModelChoiceField, which takes a QuerySet and will give you back an instance, rather than an id.

See https://docs.djangoproject.com/en/3.0/ref/forms/fields/#fields-which-handle-relationships

(If you do have an id you can assign to department_id which is created automatically for department.)

But it looks like you’re doing everything right…

1 Like

Wow, that’s fantastic it works! Thanks so much.

Do you mind me asking one other thing on the same subject?

In my registration form, I wanted the user to be able to specify a new department if it was’t already there (long story).

So, what I was doing before (when hitting the error) was creating the choices List and then appended an “Other” Tuple to the list, if the user selected that I make a new field visible on the page to allow them to enter a new department name.

Then, when the form is submitted, if the “new dept” field is populated it would first create the new department, before adding the user with the new department ID.

Does this make sense?

To achieve this I think I need to;

  1. Force an additional Tuple into the query set of (‘Other’,'other), not sure if this can be done?
  2. Before the user is created, create a new department with the name from the additional UI field.
  3. Get the new company instance and pass that through to the user creation instead.

Am I talking complete madness here? Or do you have any thoughts on how this could be done ?

Thanks again for the quick response,
Paul

1 Like

Not complete madness, no. :slightly_smiling_face:

You might need some JavaScript to make this work well but…

If your choice fields wasn’t required, it would have a empty value -------. If that were selected you could allow additional fields to create the department. (You’d need some logic for that.)

It might be better to allow creating the department with an API call, and then refresh the choices.

Or the Admin uses a pop-up.

Or…

Lot’s of options. (The difficulty is the ModelChoiceField won’t validate unless the Department is already in the QuerySet you pass it, so you have to solve that somehow…)

Thanks again for the quick response, I was just thinking maybe a popup would work better.

I’ll have a play around.