I have a Custom User model with a team field. I also have a Team model with a ManyToManyField for the Custom Users.
I have a template that allows a user to create a team using whatever Team Name they want. Upon creation, I want that user's Team to be assigned but the team primary key isn't created until the Team is created so how do I get that primary key id into the Custom User model?
My direction of thought is that I would perform a user save after the "create-team" form save in the views, but I'm not sure how to do that.
models.py
class Team(models.Model):
team_id = models.BigAutoField(auto_created=True, primary_key=True)
team_name = models.CharField(max_length=35, null=False, default='YourTeam')
team_type = models.CharField(choices=MEMBERSHIP_CHOICES, default='Free', max_length=30)
num_users = models.IntegerField(default=1)
emails = models.ManyToManyField('CustomUser', related_name='teamemails')
class CustomUser(AbstractUser):
username = None
first_name = models.CharField(max_length=255, unique=False, verbose_name='first name')
last_name = models.CharField(max_length=255, unique=False, verbose_name='last name')
email = models.EmailField(max_length=255, unique=True)
team = models.ForeignKey(Team, on_delete=models.SET_NULL, null=True, blank=True, related_name='userteam')
team_leader = models.BooleanField(default=False)
team_member = models.BooleanField(default=False)
forms.py
class CreateTeamForm(forms.ModelForm):
team_name = forms.CharField(label='Team Name', required=True)
class Meta:
model = Team
fields = ['team_name']
views.py
#verified_email_required
def create_team(request):
template = 'users/create_team.html'
if request.method == "POST":
form = CreateTeamForm(request.POST)
if form.is_valid():
form = form.save(commit=False)
form.team_name = request.team_name
form.save()
messages.success(request, 'Team Created!')
return redirect('home')
else:
messages.error(request, 'Oops! Something went wrong')
else:
form = CreateTeamForm()
context = {
'form':form,
}
return render(request, template, context)
Related
I have a form class (incorrect) :
class TeamGoalForm(ModelForm):
class Meta:
employees = forms.ModelMultipleChoiceField(queryset=Employee.objects.filter(departament=Department.objects.get(manager=Manager.objects.get(end_user_id = request.user.username.upper())),widget=forms.CheckboxSelectMultiple()))
department = forms.ModelChoiceField(queryset=Department.objects.all())
model = TeamGoal
fields = '__all__'
widgets = {
'employees' : forms.Select(attrs={'class': 'form-control', 'placeholder':'Select employees'}),
}
'department':forms.Select(attrs={'class': 'form-control', 'placeholder':'Select department'}),
I want to pass parameter request.user.username.upper() which I have in my view.py. How to implement this in my TeamGoalForm?
my view.py
#login_required(login_url='login')
def add_team_goal(request):
form = TeamGoalForm(is_manager(request))
if request.method == 'POST':
form = TeamGoalForm(request.POST)
if form.is_valid():
form.save()
return redirect('team_goal')
team = get_team(request)
if team.exists():
return render(request, 'smth.html', {'form':form,'team':team})
My Employee model:
# Employee section
class Employee(models.Model):
name = models.CharField(max_length=30, verbose_name='Name')
lastname = models.CharField(max_length=30, verbose_name='Lastname')
.............
history = HistoricalRecords()
def __str__(self):
return self.name + ' ' + self.lastname
My Department:
class Department(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=30)
.........
manager = models.ForeignKey(Manager, related_name='manager_name', null=True, on_delete = models.SET_NULL)
history = HistoricalRecords()
My Managers:
class Manager(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=30)
lastname = models.CharField(max_length=30)
history = HistoricalRecords()
def __str__(self):
return self.name + ' ' + self.lastname
My TeamGoal:
class TeamGoal(models.Model):
team_goal_title = models.CharField(max_length=30, verbose_name='Title')
team_goal_description = models.CharField(max_length=100, blank=True, verbose_name='Description')
department = models.ForeignKey(Department, verbose_name='Department', on_delete = models.CASCADE, related_name='+', blank=True, null=True, help_text=u'If you assign the team goal for the whole department, please fill only Department field and skip Employee field.')
employees = models.ManyToManyField(Employee, null=True, blank=True, symmetrical=False, related_name='employee_name')
......
history = HistoricalRecords()
In my app I can create Team goal for whole department or for specific group of employees.
I would really advise not to give Manager the same name as a user and then match on that: it makes keeping records in sync quite hard. You can link to the user model with:
from django.conf import settings
class Manager(models.Model):
id = models.AutoField(primary_key=True)
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE
)
history = HistoricalRecords()
def __str__(self):
return f'{self.user.first_name} {self.user.lastname}'
you can pass the user as parameter to the ModelForm and then filter the queryset:
class TeamGoalForm(ModelForm):
def __init__(self, *args, user=None, **kwargs):
super().__init_(*args, **kwargs)
if user is not None:
self.field['employees'] = Employee.objects.filter(
department__manager__user=user
)
class Meta:
model = TeamGoal
fields = '__all__'
widgets = {
'employees' : forms.SelectMultiple(attrs={'class': 'form-control', 'placeholder':'Select employees'}),
'department':forms.SelectMultiple(attrs={'class': 'form-control', 'placeholder':'Select department'})
}
and in the view pass the logged in user to the TeamGoalForm:
#login_required(login_url='login')
def add_team_goal(request):
if request.method == 'POST':
form = TeamGoalForm(request.POST, user=request.user)
if form.is_valid():
form.save()
return redirect('team_goal')
else:
form = TeamGoalForm(user=request.user)
team = get_team(request)
return render(request, 'smth.html', {'form':form,'team':team})
I have models: Group and Members.
Groups have many members, but when a Group is created, currentUser automatically becomes a Member.
I'm doing everything in single request and I have problem with getting id createdGroup.
My models:
class Group(models.Model):
groupName = models.CharField(max_length=100)
description = models.CharField(max_length=255)
inviteKey = models.UUIDField(default=uuid.uuid4,
unique=True,
editable=False)
class Members(models.Model):
userId = models.ForeignKey(User, on_delete=models.CASCADE)
groupId = models.ForeignKey(Group, on_delete=models.CASCADE)
Form:
class GroupForm(forms.ModelForm):
groupName = forms.CharField(label='Name', max_length=100)
description = forms.CharField(label='Description', max_length=255)
inviteKey: forms.CharField(label='Invite Key')
class Meta:
model = Group
fields = ['groupName', 'description']
View:
def createGroup(request):
if request.method == "POST":
form = GroupForm(request.POST)
if form.is_valid():
form.save()
currentUser = request.user
print('group id', request.POST.get('id', ''))
#after group creation i would add current member
addMember(currentUser, True, True) # should be currentUser, createdGroup, True
messages.success(request, f'Group created')
return redirect('/')
else:
form = GroupForm()
return render(request, 'group/createGroup.html',{'form': form})
How can I get the newly created Group's id?
I've tried something like this:
group = request.POST.get('id', '')
When I console.log(request.POST) I'm getting only (name, description)
try this:
new_group = form.save()
id = new_group.id
the id is created when you save the form triggert by the request... so it can't be in the request!
I have a custom user model from AbstractBaseUser and BaseUserManager. The user model is extended to a model called Employee. The employee model is related with(Foreignkey) two other model named WorkExperience and education. A single template form is designed with Employee, WorkExperience and Education modelform.
models.py:
class Employee(models.Model):
"""
Create employee attributes
"""
employee_user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)
e_id = models.IntegerField(unique=True, null=True)
first_name = models.CharField(max_length=128, null=True)
last_name = models.CharField(max_length=128, null=True)
gender_choices = (
('Male', 'Male'),
('Female', 'Female'),
)
......
#receiver(post_save, sender=UserProfile)
def create_or_update_user_profile(sender, instance, created, **kwargs):
if created:
Employee.objects.create(employee_user=instance, email=instance.email)
instance.employee.save()
class WorkExperience(models.Model):
"""
Stores employee previous work experiences
"""
employee_user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)
employee = models.ForeignKey('Employee', related_name='we_employee', on_delete=models.CASCADE, null=True)
previous_company_name = models.CharField(max_length=128, null=True)
job_designation = models.CharField(max_length=128, null=True)
from_date = models.DateField(null=True)
to_date = models.DateField(null=True)
job_description = models.CharField(max_length=256, null=True)
class Education(models.Model):
"""
Stores employee education background
"""
employee_user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)
employee = models.ForeignKey('Employee', related_name='edu_employee', on_delete=models.CASCADE, null=True)
institution_name = models.CharField(max_length=128, null=True)
degree = models.CharField(max_length=128, null=True)
passing_year = models.IntegerField(null=True)
result = models.DecimalField(max_digits=5, decimal_places=2, null=True)
I have a CreateView of this three models. I have three modelform. I implemented CRUD using this modelforms. My problem is in UpdateView. When I call UpdateView an error is showing stating WorkExperience matching query does not exist.I think the query is not correct.
views.py:
class EmployeeUpdateView(LoginRequiredMixin, UpdateView):
"""
Update a created a employee
"""
login_url = '/authentication/login/'
template_name = 'employee/employee_update_form.html'
form_class = EmployeeAddModelForm
work_form_class = WorkExperienceForm
education_form_class = EducationForm
context_object_name = 'employee'
model = Employee
queryset = Employee.objects.all()
# Override default get method
def get(self, request, *args, **kwargs):
id_ = self.kwargs.get("id")
employee_id = Employee.objects.get(id=id_)
work_info = WorkExperience.objects.get(employee=employee_id)
education_info = Education.objects.get(employee=employee_id)
form = self.form_class(instance=employee_id)
work_form = self.work_form_class(prefix='work_form', instance=work_info)
education_form = self.education_form_class(prefix='education_form',instance=education_info)
return render(request, self.template_name, {
'form': form,
'work_form': work_form,
'education_form': education_form,
'supervisor_assigned': employee_id.supervisor_select
}
)
# Override default post method
def post(self, request, *args, **kwargs):
id_ = self.kwargs.get("id")
employee_id = Employee.objects.get(id=id_)
work_info = WorkExperience.objects.get(employee=employee_id)
education_info = Education.objects.get(employee=employee_id)
form = self.form_class(request.POST, instance=employee_id)
work_form = self.work_form_class(request.POST, prefix='work_form', instance=work_info)
education_form = self.education_form_class(request.POST, prefix='education_form',instance=education_info)
# Check form validation
if form.is_valid() and work_form.is_valid() and education_form.is_valid():
instance = form.save()
work = work_form.save(commit=False)
education = education_form.save(commit=False)
work.employee = instance
education.employee = instance
work.save()
education.save()
return redirect('employee:employee-list')
return render(request, self.template_name, {
'form': form,
'work_form': work_form,
'education_form': education_form
}
)
urls.py:
urlpatterns = [
path('employee-list/', EmployeeListView.as_view(), name='employee-list'),
path('employee-add/', EmployeeAddView.as_view(), name='employee-add'),
path('employee-list/<int:id>/', EmployeeDetailView.as_view(), name='employee-detail'),
path('employee-list/<int:id>/update/', EmployeeUpdateView.as_view(), name='employee-update'),
How can I modify my query? i think my query is not correct.
you need to use foreign Key to use the employee id :
work_info = WorkExperience.objects.get(employee__id=employee_id)
I Hope it works fine
I'm really having some trouble with this. I've got some custom user's setup and those users can be attached to companies via foreign key. I'm just having trouble saving them. I've tried a ton of different variations of getting the user attached to a company and I just can't crack it. The forms do work and it does both create a "customer" and a "customer company".
I know this needs to be a variation of:
if customer_form.is_valid() and customer_company_form.is_valid():
customer_company = customer_company_form.save()
customer = customer_form.save(commit=False)
customer.user = customer_company
customer_company.save()
models.py
class CustomerCompany(models.Model):
COUNTRIES = (
('USA', 'United States'),
('CAN', 'Canada')
)
name = models.CharField(max_length=100, blank=True, unique=True)
website = models.CharField(max_length=100, blank=True)
phone = models.CharField(max_length=10, blank=True)
address = models.CharField(max_length=100, blank=True)
city = models.CharField(max_length=255, blank=True)
state = USStateField(blank=True, null=True)
us_zipcode = USZipCodeField(blank=True, null=True)
ca_province = models.CharField(max_length=50, blank=True, null=True)
ca_postal_code = models.CharField(max_length=7, blank=True, null=True)
country =models.CharField(max_length=3, choices=COUNTRIES,
blank=True)
def get_absolute_url(self):
return reverse('accounts:customer_company_detail',kwargs={'pk':self.pk})
def __str__(self):
return self.name
class Customer(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE,
primary_key=True, related_name='customer_profile')
company = models.ForeignKey(CustomerCompany, on_delete=models.CASCADE, null=True)
phone = models.CharField(max_length=10)
def __str__(self):
return self.user.first_name + ' ' + self.user.last_name
forms.py
class CustomerSignupForm(UserCreationForm):
first_name = forms.CharField(max_length=50, required=True)
last_name = forms.CharField(max_length=50, required=True)
phone = forms.CharField(max_length=10, required=True)
email = forms.EmailField(required=True)
class Meta(UserCreationForm.Meta):
model = User
#transaction.atomic
def save(self, commit=True):
user = super(CustomerSignupForm, self).save(commit=False)
user.is_customer = True
user.first_name = self.cleaned_data.get('first_name')
user.last_name = self.cleaned_data.get('last_name')
user.email = self.cleaned_data.get('email')
user.save()
customer = Customer.objects.create(user=user)
customer.phone = self.cleaned_data.get('phone')
customer.save()
return user
class CustomerCompanyCreateForm(forms.ModelForm):
ca_province = CAProvinceField(required=False, label="Province")
ca_postal_code = CAPostalCodeField(required=False, label="Postal Code")
class Meta:
model = CustomerCompany
fields = ['name', 'website', 'phone', 'address', 'city', 'state',
'us_zipcode', 'country', 'ca_province', 'ca_postal_code']
labels = {
"us_zipcode": "Zipcode",
}
views.py Updated with working code
def customer_signup(request):
if request.method == 'POST':
customer_form = CustomerSignupForm(request.POST)
customer_company_form = CustomerCompanyCreateForm(request.POST)
if customer_form.is_valid() and customer_company_form.is_valid():
# first save the user object
user_obj = customer_form.save(commit=False)
# Then use this object to get to my Customer model via the related name
customer = user_obj.customer_profile
# now save the CustomerCompany
company = customer_company_form.save()
# attach the customer to the Company
customer.company = company
# now fully save the customer after he's attached to his company
customer.save()
return redirect('customer_dashboard:customer_dashboard')
else:
messages.error(request, 'Please correct the errors below.')
else:
customer_form = CustomerSignupForm()
customer_company_form = CustomerCompanyCreateForm()
return render(request, 'accounts/registration/customer_signup_combined.html', {
'customer_form' : customer_form,
'customer_company_form' : customer_company_form,
})
You're saving both forms in your view but you're not connecting the two objects.
Calling save on the customer_form will return a User object since its a User ModelForm. You can use this object to get to the Customer object via the customer_profile related_name and set the company field to the Company instance returned when you save the customer_company_form.
It should look like this:
if customer_form.is_valid() and customer_company_form.is_valid():
user_obj = customer_form.save(commit=True)
customer = user_obj.customer_profile
company = customer_company_form.save(commit=True)
customer.company = company
customer.save()
return redirect('customer_dashboard:customer_dashboard')
What i am trying to achieve is that i want to extend the profile model further to either teacher or student. In the signup form I added a choice field where user select whether he is teacher or student. Below is my model structure.
class Profile(UserenaLanguageBaseProfile):
""" Default profile """
GENDER_CHOICES = (
(1, _('Male')),
(2, _('Female')),
)
user = models.OneToOneField(User,
unique=True,
verbose_name=_('user'),
related_name='profile')
gender = models.PositiveSmallIntegerField(_('gender'),
choices=GENDER_CHOICES,
blank=True,
null=True)
class Teacher(Profile):
profile = models.OneToOneField(Profile,
unique=True,
verbose_name=_('profile'),
related_name='teacher')
home_address = models.CharField(_('home_address'), max_length=255, blank=True)
home_phone = models.CharField(_('home_phone'), max_length=30, blank=True)
cell_phone = models.CharField(_('cell_phone'), max_length=30, blank=True)
experience = models.IntegerField(default = 0)
summary = models.TextField(_('summary'), max_length=500, blank=True)
class Student(Profile):
profile = models.OneToOneField(Profile,
unique=True,
verbose_name=_('profile'),
related_name='student')
grade = models.CharField(_('grade'), max_length=50, blank=True)
I am overriding the signup save method as:
def save(self):
new_user = super(SignupFormExtra, self).save()
new_user.first_name = self.cleaned_data['first_name']
new_user.last_name = self.cleaned_data['last_name']
new_user.save()
if self.cleaned_data['teacher_or_student'] == 'teacher':
teacher = Teacher(profile = new_user.get_profile())
teacher.save()
elif self.cleaned_data['teacher_or_student'] == 'student':
student = Student(profile = new_user.get_profile())
student.save()
return new_user
When teacher.save() or student.save() method is called it raises an integrity error that "(1048, "Column 'user_id' cannot be null")" but i am not creating a new user instance here i am trying to assign the newly created profile_id to teacher or student model. I am doing in the wrong way?? what should I do?
As the error says you can't create a Student or Teacher without user as you've defined it as a non nullable field.
Make sure you're passing your class the new_user you've defined..
# ...
new_user.save()
if self.cleaned_data['teacher_or_student'] == 'teacher':
teacher = Teacher(profile = new_user.get_profile(), user=new_user)
teacher.save()
elif self.cleaned_data['teacher_or_student'] == 'student':
student = Student(profile = new_user.get_profile(), user=new_user)
student.save()
I might be wrong, but why do you subclass your models from Profile model (so you have a "user" field in it already), and right after you have a "profile" OneToOneField field for Profile model again?