Employees Creating Customers for one Business

Hi, I don’t know if I can ask this type of question here. If not I will avoid this in the future; this is my first time using Django forums. In my project a Business Owner can create an Employee. The Business Owner’s, Business, is automatically attached to the employee. See view function below:

def employeeCreation(request):
	"""Let's Business Owner Create an Employee with the Business name saved in a column in the DB."""
	if request.method == "POST":
		form = NewUserForm(request.POST)
		if form.is_valid():
			form.instance.company_name = request.user.company_name
			form.instance.user = request.user
			user = form.save()
			messages.success(request, "You Have Created An Employee" )
			return redirect("user-homepage")
		else:
			messages.error(request, "Unsuccessful registration: Please make sure you met this criteria")
	form = NewUserForm()
	return render (request, "registration/employee_creation.html", context={"register_form":form})
def searchUsers(request):
"""in the works . . """"
    results = []
    if request.method == "GET":
        query = request.GET.get('search')
        if query == '':
            query = 'None'
	    #customer = Model.objects.filter(request.user.company_name)
        results = Model.objects.filter(Q(customer__icontains=query))
    return render(request, 'search_users.html', {'query': query, 'results': results})

I need an Employee to create a Customer next. This is a little trickier because I have to attach two instances to the Customer: The business name (easy) and the fact that they are a Customer (not so easy).

If I don’t attach that they are a customer, I can’t filter both business name and customer for the Employee to later search Customers within only their business. I have not been able to find any videos, documentation, or anything online explaining how to get Employees to search for customers only for their business. Can I add anything to my code to get that to work? I know how to do basic Q searches and filter searches if that helps.

Once again, if I can’t get code help here please let me know and I will gladly not post this type of question. This is my first time using Django Forums website.

Welcome! Yes, this type of question is most appropriate here.

Let’s start with the fundamentals here - what do these models look like? (Employee, Business, and Customer) Making sure that your models are appropriate is the first step in ensuring your views can accurately represent the business requirements.

1 Like

Thank you, my model is below. I don’t have separate models here because I have been messing around with different methods: groups, roles, and different classes for each User. But I have read keeping users using the same registration process and in the same table on the database is superior, so I am trying to go in that direction. This means using the same registration form for all Users and just displaying only what I want each user to fill out on the HTML. So I will make certain fields invisible and optional in the long run to achieve this.

class NewUser(AbstractUser):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    company_name = models.CharField(max_length=50, blank=True)
class NewUserForm(UserCreationForm):
	email = forms.EmailField(required=True)
	class Meta:
		model = NewUser
		fields = ("username", "email", "password1", "password2", "first_name", "last_name", "company_name", )

	def save(self, commit=True):
		user = super(NewUserForm, self).save(commit=False)
		user.email = self.cleaned_data['email']
		if commit:
			user.save()
		return user

So it looks like you have a User, and those users can either be an Employee or Customer? Do you also have a model for Business? (If not, you probably should.)

Superficially and generically, it looks to me like there would be a many-to-one relationship of Employee to Business, and a many-to-many relationship between Customer and Business.

What it really seems to me is that you would be better served by fleshing out your models a little more before diving into the code.

1 Like

I changed my models to reflect your ideas.

Hi, I am following your initial steps of adding the relationships below. I am getting an error when I tried to add the ‘customer’ field to my form. I was under the false impression that if I added ‘customer’ to the Business class as a many to many, I could render it out on my form. Is that not true? Is the better way to set up that relationship?

django.core.exceptions.FieldError: Unknown field(s) (customer) specified for User

The final goal here is to let the superuser creates employees, and the employees create customers. The views will automatically add the employee business_name to the customer (I have working logic for this); however, the final goal that I don’t have working properly is getting the views to automatically add the boolean OR string of ‘customer’ to a customer. That way later employees can search customers only for their business.

Thank you for helping me with this; I am assuming this is pretty common to do; I just haven’t found any videos, books, or anything explaining how to do this properly, it’s probably my weakness in creating relationships within classes. This is really good practice for me to get me to the next level of understanding of how relationships can lead to an easier time creating filters and queries in my views.

class User(AbstractUser):
    """User can be Employee or Customer"""
    business = models.ForeignKey("Business", on_delete=models.CASCADE)

class Customer(models.Model):
    customer = models.CharField(max_length=50)
    employee = models.CharField(max_length=50)

class Business(models.Model):
    business_name = models.CharField(max_length=50)
    customer = models.ManyToManyField(Customer)
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from .models import User

      
class UserForm(UserCreationForm):

	class Meta:
		model = User
		fields = ("username", "email", "password1", "password2", "first_name", "last_name", "customer", "business" , 'employee')

Regarding your models, I was more thinking along the lines:
(as examples - not suitable to just copy/paste into your code)

class User(AbstractUser):
    """User can be Employee or Customer"""

class Customer(models.Model):
    """ Customer-specific information """
    user = models.OneToOneField(User)
    businesses = models.ManyToManyField(Business)

class Employee(models.Model):
    """ Employee-specific information """
    user = models.OneToOneField(User)
    business = models.ForeignKey(Business)

class Business(models.Model):
    business_name = models.CharField(max_length=50)

If you have an instance of User named user, then user.customer (if it exists) is the information you need for that customer, in addition to being able to identify all the businesses they are a customer to. Likewise, user.employee is the employee-related information, and user.employee.business is the business that they are an employee of.

1 Like

Hi, I think I am headed down the right path; my current code is below, what would I need to learn to avoid these errors:

site_users.Employee.username: (fields.E305) Reverse query name for ‘site_users.Employee.username’ clashes with reverse query name for ‘site_users.Employee.user’.
** HINT: Add or change a related_name argument to the definition for ‘site_users.Employee.username’ or ‘site_users.Employee.user’.**

I understand why I am getting the error, but am not sure how to fix it and accomplish the ultimate goal of creating these different forms and a user at the same time. I like your idea of separating the models, so I can later query search much easier, but am not sure how to get all the fields on each separate form, as the error supports. I could create the variables only in the forms.py file, but then they wouldn’t be linked to each other, and “I think” might create data redundancy, but I could be wrong. Maybe redundancy is only important with id’s.

Should I only include the first_names, last_names, etc. . in the forms.py file as CharField’s? And not as foreign keys in my different classes in models.py? Would this avoid this error? Thank you.

class Business(models.Model):
    business = models.CharField(max_length=50)

# Create your models here.
class User(AbstractUser):
    """User can be Employee or Customer"""
    business = models.ForeignKey(Business, on_delete=models.CASCADE, null=True)

class Customer(models.Model):
    """ Customer-specific information """
    user = models.OneToOneField(User,  on_delete=models.CASCADE)
    first_name = models.OneToOneField(User,  on_delete=models.CASCADE)
    last_name = models.OneToOneField(User,  on_delete=models.CASCADE)
    username = models.OneToOneField(User,  on_delete=models.CASCADE)
    business = models.ForeignKey(Business, on_delete=models.CASCADE)

class Employee(models.Model):
    """ Employee-specific information """
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    first_name = models.OneToOneField(User,  on_delete=models.CASCADE)
    last_name = models.OneToOneField(User,  on_delete=models.CASCADE)
    username = models.OneToOneField(User,  on_delete=models.CASCADE)
    business = models.ForeignKey(Business,  on_delete=models.CASCADE)

class UserForm(UserCreationForm):

	class Meta:
		model = User
		fields = ("username", "password1", "password2", "first_name", "last_name", "business", )


class EmployeeForm(UserCreationForm):

	class Meta:
		model = Customer
		fields = ("username", "password1", "password2", "first_name", "last_name", "business", )

class CustomerForm(UserCreationForm):

	class Meta:
		model = Employee
		fields = ("username", "password1", "password2", "first_name", "last_name", "business", )

def employeeCreation(request):
	"""Creates an Employee with logging Admin Off and adding the employee to the group and company"""
	if request.method == "POST":
		form = EmployeeForm(request.POST)
		if form.is_valid():
			form.instance.company_name = request.user.company_name
			form.instance.user = request.user
			user = form.save()
			messages.success(request, "You Have Created An Employee" )
			return redirect("user-homepage")
		else:
			messages.error(request, "Unsuccessful registration: Please make sure you met this criteria")
	form = EmployeeForm()
	return render (request, "registration/employee_creation.html", context={"form":form})

def customerCreation(request):
	"""Creates an Customer with logging off user and adding the customer to the group and company"""
	if request.method == "POST":
		form = CustomerForm(request.POST)
		if form.is_valid():
			form.instance.company_name = request.user.company_name
			form.instance.user = request.user
			user = form.save()
			messages.success(request, "You Have Created A Customer")
			return redirect("user-homepage")
		else:
			messages.error(request, "Unsuccessful registration: Please make sure you met this criteria")
	form = CustomerForm()
	return render (request, "registration/employee_creation.html", context={"form":form})

We need to keep working on the models - we’re still not ready to move on to code:

class Business(models.Model):
    business = models.CharField(max_length=50)

# Create your models here.
class User(AbstractUser):
    """User can be Employee or Customer"""
    business = models.ForeignKey(Business, on_delete=models.CASCADE, null=True)

class Customer(models.Model):
    """ Customer-specific information """
    user = models.OneToOneField(User,  on_delete=models.CASCADE)
    business = models.ForeignKey(Business, on_delete=models.CASCADE)

**NO! These definitions aren't needed. The User model already has these fields
    first_name = models.OneToOneField(User,  on_delete=models.CASCADE)
    last_name = models.OneToOneField(User,  on_delete=models.CASCADE)
    username = models.OneToOneField(User,  on_delete=models.CASCADE)

class Employee(models.Model):
    """ Employee-specific information """
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    business = models.ForeignKey(Business,  on_delete=models.CASCADE)

**NO! These definitions aren't needed. The User model already has these fields
    first_name = models.OneToOneField(User,  on_delete=models.CASCADE)
    last_name = models.OneToOneField(User,  on_delete=models.CASCADE)
    username = models.OneToOneField(User,  on_delete=models.CASCADE)

If you’re not comfortable with accessing models through foreign keys, you might want to review the work you have done in the Official Django Tutorial and the docs and examples at Many-to-one relationships | Django documentation | Django and Model field reference | Django documentation | Django

You’ll want to make sure you understand how these related models work before you try to build code around them.

1 Like

To my understanding and reading:

class Business(models.Model):
    business = models.CharField(max_length=50)

Below the FK creates a relationship where one business is tied to many users.

class User(AbstractUser):
    """User can be Employee or Customer"""
    business = models.ForeignKey(Business, on_delete=models.CASCADE, null=True)

Next we have a each Customer’s user_id connected to the user_id in the User table.
Then we have a FK, because there can be many Customer’s to one Business.

class Customer(models.Model):
    """ Customer-specific information """
    user = models.OneToOneField(User,  on_delete=models.CASCADE)
    business = models.ForeignKey(Business, on_delete=models.CASCADE)

#Lastly, I have the same relationships as the Customer field.

class Employee(models.Model):
    """ Employee-specific information """
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    business = models.ForeignKey(Business,  on_delete=models.CASCADE)

I think my problem is that I can’t render these forms together unless I do a multiform or just display the user form and the employee/customer form on the same HTML document.

Am I thinking correctly about this and the relationships? Or is there a better method?

Thank you

(Referring to User)

Unfortunately, I missed flagging that earlier. There should not be an FK from User to Business.

Either or both of an Employee (employee-employer relationship) and a Customer (customer-business) are related to a business - and sometimes different businesses. But User doesn’t need to be.

You can render multiple forms on a page, as long as each form is created with a different prefix.
(And then, of course, you’re also responsible for checking all the forms for validity and saving them all.)

1 Like

Hi, I am at the step in this process where I am trying to attach the business POST object to the customer or employee form.

I always do it this way and it works, but I do this with request.user and haven’t tried it with other objects before.

Goal: get the business object from the BusinessForm by using commit=false. Then take this object and attach it to the employee form to fill out the business field on that form in the BD. Now the employee will have a business stored with the employee.

def employeeCreation(request):
	if request.method == "POST":
		employee_form = EmployeeForm(request.POST)
		business_form = BusinessForm(request.POST)
		user_creation_form = UserForm(request.POST)
		if (user_creation_form.is_valid() and employee_form.is_valid() and business_form.is_valid()):
			user_creation_form.save(commit=False)
			business_form.save(commit=False)

			employee_form.instance.user = request.user # always works.
			employee_form.instance.business = request.business # ??

			user_creation_form.save()
			business_form.save()
			employee_form.save()
			
			messages.success(request, "You Have Created An Employee" )
			return redirect("user-homepage")
		else:
			messages.error(request, "Unsuccessful registration: Please make sure you met this criteria")
	employee_form = EmployeeForm()
	customer_form =  CustomerForm()
	business_form = BusinessForm()
	user_creation_form = UserForm()
	return render (request, "registration/employee_creation.html", 
		context={"user_creation_form": user_creation_form,
				"customer_form": customer_form, 
	   			"employee_form": employee_form,
				"business_form": business_form,
					})

These statements return the object of the type being created.

For example, the return value of user_creation_form.save() is the object of the type identified by the ModelForm EmployeeForm, and the return value of business_form.save() is the object of the type identified by the ModelForm BusinessForm.

What you really want to do is keep the references to those objects for later use.
For example:

new_user = user_creation_form.save(commit=False)
new_business = business_form.save(commit=False)

You can then use or modify those instances like any other model and then save those instances.

Side note: You only want to use commit=False when you want to make later alterations to those objects while doing other processing. If you’re not making further changes to the Business object, then you want to go ahead and save it at that point.

Review the docs and examples at Creating forms from models | Django documentation | Django

How would I attach the logged-on user’s business name to the employee form? So they don’t have to type it in and, so a new business with the same name isn’t created.

I was thinking this:

employee_form.instance.business = request.employee.business

But I can’t access the objects in request.employee.business or request.user.business in order to attach them to the instance of the employee form. I am trying to do the same thing as this:

			new_user= user_creation_form.save(commit=False)
			#new_business= business_form.save(commit=False)

			customer_form.instance.user = new_user

I was thinking of adding a relationship from User to Business, but you suggested in a previous post not to, so I wasn’t sure what you had in mind for how I could access the logged-on user’s business name object.

Thank you! I keep making progress on this when you share ideas. Chipping away at it.

Employee is not an attribute of request, user is.

So the reference to the Business object would be request.user.employee.business.

I got everything to work so far; however, I’m at another step in this process where I am trying to dynamically select a choice in the ChoiceField model for my User in my Employees and Customer Creation views. I have a slight idea how to do this, but it’s not working and I am not sure of the best method here.

Here is where I am at in totality:

models.py

from django.db import models
from django.contrib.auth.models import AbstractUser


# Create your models here.
class User(AbstractUser):
    """User can be Employee or Customer"""
    USER_TYPE_CHOICES = (
      (1, 'Admin or Business Owner'),
      (2, 'Employee'),
      (3, 'Customer'),
  )
    user_type = models.PositiveSmallIntegerField(choices=USER_TYPE_CHOICES)


class Business(models.Model):
    business = models.CharField(max_length=50)

class BusinessOwner(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, null=True )
    business = models.ForeignKey(Business, on_delete=models.CASCADE, null=True)

class Customer(models.Model):
    """ Customer-specific information """
    user = models.OneToOneField(User, on_delete=models.CASCADE, null=True )
    business = models.ForeignKey(Business, on_delete=models.CASCADE, null=True)

class Employee(models.Model):
    """ Employee-specific information """
    user = models.OneToOneField(User, on_delete=models.CASCADE, null=True)
    business = models.ForeignKey(Business,  on_delete=models.CASCADE, null=True, blank=True)

forms.py

from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from .models import User, Customer, Employee, Business, BusinessOwner
import django_filters

      
class CustomerFilter(django_filters.FilterSet):
    business = django_filters.CharFilter(name='business', lookup_expr='icontains')
    customer = django_filters.CharFilter(name='customer', lookup_expr='icontains')
    user = django_filters.CharFilter(name='user', lookup_expr='icontains')

    class Meta:
        model = Customer
        fields = ['business', 'customer', 'user', ]


class UserForm(UserCreationForm):

	class Meta:
		model = User
		fields = ( "username", "email", "password1", "password2", "first_name", "last_name", "user_type" )


class BusinessOwnerForm(forms.ModelForm):

	class Meta:
		model = BusinessOwner
		fields = (  )

class EmployeeForm(forms.ModelForm):

	class Meta:
		model = Employee
		fields = (  )

class CustomerForm(forms.ModelForm):

	class Meta:
		model = Customer
		fields = ( )

class BusinessForm(forms.ModelForm):

	class Meta:
		model = Business
		fields = ( "business",  )

views.py

def searchUsers(request):
    result = Customer.objects.all()
    query = request.GET.get("query")
    if query:
        result = result.filter(
		Q(user__customer__icontains=query) |
		Q(user__business__icontains=query) 
        ).distinct()
    user_filter = CustomerFilter(request.GET, queryset=result)
    return render(request, "search_users.html", {'filter': user_filter, 
						 'query': query})


######################
#BUSINESS ADMIN VIEWS#
######################

def BusinessOwnerCreation(request):
	if request.method == "POST":
		business_form = BusinessForm(request.POST)
		user_creation_form = UserForm(request.POST)
		businessowner_form = BusinessOwnerForm(request.POST)
		if (user_creation_form.is_valid() and business_form.is_valid()):

			#Attaches id of Business to Business Owner Form.
			business_id = business_form.save(commit=False)
			businessowner_form.instance.business = business_id
			#Attaches User_Id to to Business Owner Form
			new_user = user_creation_form.save(commit=False)
			businessowner_form.instance.user = new_user

			#Attaches User_Id to to User Creation Form and Business Form.
			new_user = user_creation_form.save(commit=False)
			business_form.instance.user = new_user

			user_creation_form.save()
			business_form.save()
			businessowner_form.save()
			messages.success(request, "You Have Created An Business Owner" )
			return redirect("user-homepage")
		else:
			messages.error(request, "Try creating an Employee Again something went wrong.")
	business_form = BusinessForm()
	user_creation_form = UserForm()
	return render (request, "registration/biz_owner_creation.html", 
		context={"user_creation_form": user_creation_form, 
	   			"business_form": business_form,
					})

def employeeCreation(request):
	"""Creates an Employee"""
	if request.method == "POST":
		employee_form = EmployeeForm(request.POST)
		user_creation_form = UserForm(request.POST)
		if (user_creation_form.is_valid() and employee_form.is_valid()):
			employee_form.instance.business = request.user.businessowner.business
			new_user = user_creation_form.save(commit=False)
			employee_form.instance.user = new_user
			user_creation_form.save()
			employee_form.save()
			messages.success(request, "You Have Created An Employee" )
			return redirect("user-homepage")
		else:
			messages.error(request, "Try creating an Employee Again something went wrong.")
	employee_form = EmployeeForm()
	user_creation_form = UserForm()
	return render (request, "registration/employee_creation.html", 
		context={"user_creation_form": user_creation_form, 
	   			"employee_form": employee_form,
					})


def customerCreation(request):
	"""Creates a Customer"""
	if request.method == "POST":
		customer_form  = CustomerForm(request.POST)
		user_creation_form = UserForm(request.POST)
		if (user_creation_form.is_valid() and customer_form.is_valid()):
			new_user = user_creation_form.save(commit=False)
			customer_form.instance.user = new_user
			if request.user.employee:
				customer_form.instance.business = request.user.employee.business
			else:
				pass
			if request.user.businessowner:
				customer_form.instance.business = request.user.businessowner.business
			else:
				pass
			UserForm(initial = {'user_type' : '3'})
			customer_form.save()
			user_creation_form.save()
			messages.success(request, "You Have Created A Customer")
			return redirect("user-homepage")
		else:
			messages.error(request, "Try creating a Customer Again something went wrong.")
	customer_form = CustomerForm()
	user_creation_form = UserForm()
	return render (request, "registration/customer_creation.html", 
		context={"user_creation_form": user_creation_form,
				"customer_form": customer_form, 
					})

#There are some other basics views not included here like a index, base, navbar etc . . Not applicable to this problem.

In my customerCreation function i have a line of code:
UserForm(initial = {‘user_type’ : ‘3’})

Am I on the right track here or is there a better way?

Thank you

With this structure - and the ability for a person to be both a customer and an employee, you do not want any indication on the user object to identify the type. The type(s) of a user can be determined by the presence of the related types.

1 Like

Oh okay, I was doing that so I could later add decorators to restrict users from certain pages. I will find a different way to add decorators, so I can stick to this structure. Thank you.

I’m not sure what decorators you’re going to use, but you can test for the profile class on the User model. If you have an instance of User named user, then user.customer is not null if they have a Customer profile model, and is null if they don’t. (Or user.businessowner for that reference) That’s the test you can use to determine whether or not they satisfy the requirement for that role.

1 Like

I am towards the end of this project and an answer to the original question. I have two final steps. First I have to try to fix this error, but am drawing a blank on how to fix this. I have an ‘if’ statement in my customer creation code. I am logged on as a business owner. When the request checks for an employee it says it doesn’t exist: obviously, but it should check for the business owner next and it does not.
Why isn’t it skipping the request.user.employee.business and moving onto the elif statement?
If it moved on, this code would work, I tested it without the request.user.employee.business and it works.

from django.db import models
from django.contrib.auth.models import AbstractUser


# Create your models here.
class User(AbstractUser):
    """User can be Employee or Customer"""


class Business(models.Model):
    business = models.CharField(max_length=50)

class BusinessOwner(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, null=True )
    business = models.ForeignKey(Business, on_delete=models.CASCADE, null=True)

class Customer(models.Model):
    """ Customer-specific information """
    user = models.OneToOneField(User, on_delete=models.CASCADE, null=True )
    business = models.ForeignKey(Business, on_delete=models.CASCADE, null=True)

class Employee(models.Model):
    """ Employee-specific information """
    user = models.OneToOneField(User, on_delete=models.CASCADE, null=True)
    business = models.ForeignKey(Business,  on_delete=models.CASCADE, null=True, blank=True)
def customerCreation(request):
	"""Creates a Customer"""
	if request.method == "POST":
		customer_form  = CustomerForm(request.POST)
		user_creation_form = UserForm(request.POST)
		if (user_creation_form.is_valid() and customer_form.is_valid()):
			new_user = user_creation_form.save(commit=False)
			customer_form.instance.user = new_user
			if request.user.employee.business:
				customer_form.instance.business = request.user.employee.business
			elif request.user.businessowner.business:
				customer_form.instance.business = request.user.businessowner.business
			else:
				pass
			customer_form.save()
			user_creation_form.save()
			messages.success(request, "You Have Created A Customer")
			return redirect("user-homepage")
		else:
			messages.error(request, "Try creating a Customer Again something went wrong.")
	customer_form = CustomerForm()
	user_creation_form = UserForm()
	return render (request, "registration/customer_creation.html", 
		context={"user_creation_form": user_creation_form,
				"customer_form": customer_form, 
					})

It’s not clear to me what specifically you’re trying to describe.

What specifically isn’t happening that you’re expecting to have happen? (Or is happening that you’re not expecting to see?) If you’re getting an error message, please post the complete error including the traceback. Otherwise, please provide more detail with reference to the code that you have posted what the problem appears to be.