I want to add a department field on my User model. I am using sql server as my db. I did the following in models.py
class Employee(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, db_column='user')
department = models.CharField(max_length=20, blank=True)
class Meta:
db_table = 'Employee'
Then, using stored procedure I can fill all the fields of User easily, but when I want to fill the extra field department, I get the error
RelatedObjectDoesNotExist at /fetched
User has no employee.
in views.py, where I retrieve the data from procedure:
q = User(id=result_set[i][0], username=result_set[i][1], is_staff=False,
first_name=result_set[i][4], last_name=result_set[i][3], email=result_set[i][8])
q.set_password(result_set[i][2])
q.employee.department = 'something'
q.save()
You can extend the AbstractUser to your model
In models.py
from django.contrib.auth.models import AbstractUser
class Employee(AbstractUser):
department = models.CharField(max_length=20, blank=True)
Related
I've inherited from the AbstractBaseUser as follows:
class User(AbstractBaseUser):
"""
Main User model, inherits from AbstractBaseUser
"""
# Meta
email = models.EmailField(verbose_name='email', max_length=60, unique=True)
username = models.CharField(max_length=40, unique=True) # equals to email
date_joined = models.DateTimeField(verbose_name='date joined', auto_now_add=True)
last_login = models.DateTimeField(verbose_name='last login', auto_now=True)
employee_of = models.OneToOneField(Customer, on_delete=models.SET_NULL, null=True)
So each User is linked to one and only one Customer.
Now within a view I want to access the instance of the current logged in user within the request object and get the employee_of value to get a queryset that contains all users of that customer.
def render_employees(request):
"""
Renders the employees page of the dashboard
:param request:
:return:
"""
# Return the value for the current site for css specific classes
dashboard_site = 'employees'
# Query the employees
qs_employees = User.objects.filter(employee_of=request.user.employee_of) # doesn't find field
...
However the filter doesn't work because request.user.employ_of doesn't seem to return anything. My IDE even suggests e.g. username, date_joined etc. but not employee_of.
Why's that?
class Customer(models.Model):
"""
A table that stores static data about a customer, usually a legal company
"""
legal_name = models.CharField(max_length=50)
street = models.CharField(max_length=30)
street_number = models.CharField(max_length=3)
def __str__(self):
return self.legal_name
Update:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
from applications.customer.models import Customer
from django.conf import settings
BaseUser = settings.AUTH_USER_MODEL
class User(AbstractBaseUser):
"""
Main User model, inherits from AbstractBaseUser
"""
# Relations
user = models.OneToOneField(BaseUser, related_name='user_profile', on_delete=models.CASCADE, null=True) # link to default user model
employee_of = models.OneToOneField(Customer, on_delete=models.SET_NULL, null=True, blank=True)
I linked the user to the default user model via Django admin. However in the view im still not able to access employee_of within request.user
It seems that request.user is a different model. It's User model from django.contrib.auth. https://docs.djangoproject.com/en/4.0/ref/contrib/auth/#django.contrib.auth.models.User.
What you can do about it?
In our app we have UserProfile model that have OnetoOne relation to django User.
You can then store employee_of value there.
class UserProfile(AbstractBaseUser):
user = models.OnetoOneField("auth.User", related_name="user_profile", on_delete=models.CASCADE)
employee_of = models.OneToOneField(Customer, on_delete=models.SET_NULL, null=True)
and then access request.user employees using something like
request.user.user_profile.employee_of
I have user, userprofile and company tables.
I want to create a record in company table and then assign the id of the newly created company in the userprofile foreign key before creating the user. I think it can be done using pre_save signal but I am unable to figure how. Please help.
Here's some details as AMG asked:
I have django's builtin user model
a userprofile model
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default='profile_pics/default.jpeg', upload_to='profile_pics')
bio = models.TextField(blank=True, verbose_name='Biography')
company_name = models.ForeignKey(Company, on_delete=models.CASCADE)
a company model
class Company(models.Model):
name = models.TextField(blank=True, verbose_name="Company Name")
nof = models.IntegerField(verbose_name="No. of Employees")
All three are related user and userprofile has one to one relationship, and userprofile and company has many to one relationship.
I want Company record to be created first and than that new record's reference needs to be put into userprofile.
I think I have made it clear now.
Exactly, you can use pre_save for this. You can just put this in models.py below your defined models.
from django.db.models.signals import pre_save
#receiver(pre_save, sender=Profile) # register your model to the signal pre_save
def my_callback(sender, instance, *args, **kwargs):
if not instance.company_name: # check if instance has a value for company_name
company = Company.objects.create(
name='Test',
nof=1
)
instance.company_name = company
OR
Create a default value through a function.
class Company(models.Model):
name = models.TextField(blank=True, null=True, verbose_name="Company Name") # set blank=true and null=true so you can save an empty instance
nof = models.IntegerField(blank=True, null=True, verbose_name="No. of Employees")
def profile_company_default():
return Company.objects.create()
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default='profile_pics/default.jpeg', upload_to='profile_pics')
bio = models.TextField(blank=True, verbose_name='Biography')
company_name = models.ForeignKey(Company, on_delete=models.CASCADE, default=profile_company_default) # add function as default value
EDIT
To edit company after save.
profile = Profile.objects.create(key="value")
profile.company.name = "Company Name"
profile.company.nof = 5
profile.save()
I am new to django and am trying to set up a simple employee timesheet site that has multiple users. I set up two models one for the individual employee that has a ForeignKey of the base django user and a timesheet model that has a ForeignKey of the employee model. I'm not sure this is correct because when I use my registration form it just creates the base django user and not the "Employee" so when I want to create a new timesheet entry only the one employee is set up (set up with admin page). Can someone with more django experience tell me if there is a better way to do this (different model relationship, etc)
from django.urls import reverse
from django.core.validators import MinValueValidator, MaxValueValidator
from django.utils import timezone
import datetime
from django.contrib.auth.models import User
class Employee(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='employee')
payRate = models.DecimalField(max_digits=4, decimal_places=2, default=15.00, verbose_name=("Pay"))
vacTotal = models.DecimalField(max_digits=5, decimal_places=2, default=200.00, verbose_name=("Vacation"))
# META CLASS
class Meta:
verbose_name = 'employee'
verbose_name_plural = 'employees'
# TO STRING METHOD
def __str__(self):
return f"{self.user}"
class Tsheet(models.Model):
# CHOICES
WORK_CHOICES= (
('W', 'Regular Work'),
('V', 'Vacation'),
('S', 'Sick',),
('C','Call In'),
)
# DATABASE FIELDS
name = models.ForeignKey(Employee, on_delete=models.CASCADE, related_name='name')
workType = models.CharField(max_length=15,choices=WORK_CHOICES)
workDate = models.DateField(verbose_name=("Date"), default=datetime.date.today, editable=True)
workDescription = models.CharField(max_length=200)
workHours = models.DecimalField(max_digits=4, decimal_places=2, default=8.00, verbose_name=("Hours"))
workReviewed= models.BooleanField(default=False)
slug = models.SlugField(max_length=50, unique=True,
help_text='Unique value for timesheet entry URL, created automatically from name.')
# META CLASS
class Meta:
verbose_name = 'tsheet'
verbose_name_plural = 'tsheets'
# TO STRING METHOD
def __str__(self):
return f"{self.name} - {self.workDate} - {self.workHours} - {self.workType}"
# SAVE METHOD
# ABSOLUTE URL METHOD
def get_absolute_url(self):
return reverse('entry-detail', kwargs={'pk': self.pk})```
The right way to approach this is to extend the AbstractUser and add the fields there:
class User(AbstractUser):
payRate = models.DecimalField(max_digits=4, decimal_places=2, default=15.00, verbose_name=("Pay"))
vacTotal = models.DecimalField(max_digits=5, decimal_places=2, default=200.00, verbose_name=("Vacation"))
Then you have a single table with all the data from the default Django User as well as your specific fields
I'm currently trying to setup some database models in djangos ORM. however im unable to figure out how i'm supposed to reference another models many-to-many- field.
Project model
class Project(models.Model):
projectName = models.CharField(max_length=200)
users = models.ManyToManyField(get_user_model())
projectOwner = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, related_name='projectowner', default=1)
The users = models.manytomanyfield(get_user_mode()) works fine
and generates the correct relation in the database.
now i want to add a new model that adds a many to many relation between rights and project_user
so what the end result tables are supposed to look like:
project:
projectname - string
projectowner - id of referenced user
user: django orm auth user model
rights:
name
description
etc
project_user:
id
project_id
user_id
rights_projectuser:
id
rights_id
project_user_id
now that last one (rights_projectuser) is what i dont know how to make.
You need to turn "project_user" into a through model that you can then add the many to many relationship to.
class Project(models.Model):
projectName = models.CharField(max_length=200)
users = models.ManyToManyField(get_user_model(), through='ProjectUser')
class ProjectUser(models.Model):
project = models.ForeignKey(Project, on_delete=models.CASCADE)
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
rights = models.ManyToManyField(Right)
i now get the following problem when running this code:
from django.db import models
from django.contrib.auth import get_user_model
User = get_user_model()
class Project(models.Model):
projectName = models.CharField(max_length=200)
users = models.ManyToManyField(get_user_model(), through='ProjectUser')
projectOwner = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, related_name='projectowner', default=1)
class Right(models.Model):
name = models.CharField(max_length=200)
description = models.CharField(max_length=1000)
class ProjectUser(models.Model):
user_id = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
project_id = models.ForeignKey(Project, on_delete=models.CASCADE)
rights = models.ManyToManyField(Right)
ValueError: Cannot alter field wspingpong.Project.users into wspingpong.Project.users - they are not compatible types (you cannot alter to or from M2M fields, or add or remove through= on M2M fields)
I know we can require that the SlugField be unique with unique=True option, but is it possible to require it to be unique only for a particular user, so two different user could have the same SlugField but a user cannot have two identical slugField?
models. py:
from django.db import models
from django.contrib.auth.models import User
class ezApp(models.Model):
name = models.SlugField(max_length=50, unique=True )
date_created = models.DateTimeField('date created')
date_updated = models.DateTimeField('date updated')
created_by = models.ForeignKey(User)
in_use = models.BooleanField()
You'll want to use unique_together as detailed here:
https://docs.djangoproject.com/en/dev/ref/models/options/#unique-together
class MyModel(models.Model):
# ...
class Meta:
unique_together = ('name', 'created_by')
You'll have to do some babysitting at the form level too, so the user gets usable error messages when they try to add duplicate names.