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
Related
I am very new to Django and trying to make my first project. I find it difficult to display currently logged in user's ID on the list in Django admin model.
I found a solution of how to get the appriopriate ID thanks to Shang Wang (Django admin: Get logged In users id in django)
But I don't know how to display this ID on the list, right next to Patient ID, Unit and Create time (mentioned in the code below).
My admin.py looks like this :
class GeneralAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
obj.user = request.user
super(GeneralAdmin, self).save_model(request, form, obj, change)
list_display = ('id_patient', 'unit', 'create_time')
search_fields = ('id_patient', 'unit', 'create_time')
readonly_fields = ('unit', 'Birth_date','create_time',)
Edit 2: my models.py file:
from django.db import models
from datetime import date, datetime
from django.contrib.auth.models import User
class Unit(models.Model):
id = models.AutoField(primary_key=True)
description = models.CharField(max_length=300)
class Patient(models.Model):
id = models.AutoField(primary_key=True, verbose_name='Patient ID')
unit = models.ForeignKey(Unit, on_delete=models.CASCADE)
Birth_date = models.DateField()
introducer = models.ForeignKey(User,
help_text = "This field will be calculated automatically",
blank=True, null=True, on_delete=models.CASCADE)
#here I try to get current user's ID
def save(self, *args, **kwargs):
self.introducer = User.username #here I get an error
super().save(*args, **kwargs)
class General(models.Model):
id = models.AutoField(primary_key=True)
id_patient = models.ForeignKey(Patient, on_delete=models.CASCADE)
unit = models.ForeignKey(Unit, help_text = "This field will be calculated automatically", blank=True, null=True, on_delete=models.CASCADE)
Birth_date = models.DateField(blank=True, null=True, help_text = "This field will be calculated automatically")
create_time = models.DateTimeField(blank=True, null = True, default = datetime.now())
def save(self, *args, **kwargs):
self.Birth_date = self.id_patient.Birth_date
self.unit = self.id_patient.unit
super().save(*args, **kwargs)
class Primary_Treatment_EBRT(models.Model):
id = models.AutoField(primary_key=True)
unit = models.ForeignKey(Unit, help_text = "This field will be calculated automatically", blank=True, null=True, on_delete=models.CASCADE)
Birth_date = models.DateField(blank=True, null=True, help_text = "This field will be calculated automatically")
create_time = models.DateTimeField(blank=True, null = True, default = datetime.now())
id_patient = models.ForeignKey('Patient', on_delete=models.CASCADE)
def save(self,*args, **kwargs):
self.Birth_date = self.id_patient.Birth_date
self.unit = self.id_patient.unit
super().save(*args, **kwargs)
How to put obj.user's ID into list_display to display it on the list like id_patient, unit, or create_time?
Problem RESOLVED:
My admin.py change:
class PatientAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change, *args, **kwargs):
obj.user = request.user
obj.create_time = datetime.now()
super(PatientAdmin, self).save_model(request, obj, form, change, *args, **kwargs)
My models.py change:
create_time = models.DateTimeField(blank=True, null = True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True,
null=True, on_delete=models.CASCADE)
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'm building a small webstore , in the product page i put the order form using FormMixin and TemplateView, when i submit the order i get a "Direct assignment to the forward side of a many-to-many set is prohibited. Use product.set() instead." error
Bellow you can check the code
Models.py
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=255, unique=True, )
description = models.TextField(max_length=1500)
class Meta:
verbose_name_plural = "categories"
def __str__(self):
return self.name
class Product(models.Model):
name = models.CharField(max_length=255)
description = models.TextField()
nominal_price = models.PositiveIntegerField(verbose_name='prix normal',)
reduced_price = models.PositiveIntegerField(blank=True, null=True)
quantity = models.PositiveIntegerField(default=10)
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='products')
photo = models.ImageField(upload_to="img/products/", default="img/products/user_default.png")
def __str__(self):
return self.name
class Customer(models.Model):
full_name = models.CharField(max_length=150)
address = models.CharField(max_length=1500, null=True)
phone = models.IntegerField()
city = models.CharField(max_length=100)
email = models.EmailField(null=True)
class Order (models.Model):
product = models.ManyToManyField(Product, through='OrderProduct')
customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
class OrderProduct(models.Model):
order = models.ForeignKey(Order, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
Views.py
class ProductDetailView(FormMixin, TemplateView):
model = Product
template_name = 'product.html'
form_class = OrderForm
def get_success_url(self):
return reverse('index')
def post(self, request, *args, **kwargs):
context = self.get_context_data()
form = OrderForm(request.POST)
if context['form'].is_valid():
product = get_object_or_404(Product, name=self.kwargs['product_name'])
customer = form.save()
Order.objects.create(product=product, customer=customer)
return super(TemplateView, self)
def get_context_data(self, **kwargs):
context = super(ProductDetailView, self).get_context_data(**kwargs)
context['product'] = Product.objects.get(name=self.kwargs['product_name'])
context['form'] = self.get_form()
return context
urls.py
path('', views.ProductListView.as_view(), name='index'),
Did i missed something
For handling many-to-many relations, you cannot directly set the product from Order. Also you would need to create the order first before you can set or add a product:
order = Order.objects.create(customer=customer)
order.product.add(product)
I am making a CV page,
I want to link my Skill, Language etc class(table) to Main Person table/class,
But for that, I need to submit skill table first because my person table contains the foreign key for skills.
But as per CV form name & personal info comes first.
Also, I can put the whole form on one page but I want to go to the next page for each sub information, so is it possible to pass the request data from one class-based view to another class-based view.
models.py
from django.db import models
from django.core.validators import MinLengthValidator
from django.conf import settings
import datetime
class Workexperience(models.Model):
work = models.CharField(null=True, blank=True,
max_length=256,
help_text='eg: Juniorengineer: at L&T ')
person = models.ForeignKey('Person', on_delete=models.CASCADE, blank=True, null=False, default=1 )
def __str__(self):
return self.work
class Education(models.Model):
school = models.CharField(max_length=200)
college = models.CharField(null=True, blank=True,max_length=200)
person = models.ForeignKey('Person', on_delete=models.CASCADE, blank=True, null=False, default=1 )
def __str__(self):
return self.school
class Skills(models.Model):
skill = models.CharField(
max_length=256,
help_text='Add skills sperated by commas eg: programming, Matlab')
person = models.ForeignKey('Person', on_delete=models.CASCADE, blank=True, null=False, default=1 )
def __str__(self):
return self.skill
class Languages(models.Model):
language = models.CharField(
max_length=256,
help_text='Add language sperated by commas eg: English, Gujarati')
person = models.ForeignKey('Person', on_delete=models.CASCADE, blank=True, null=False, default=1 )
def __str__(self):
return self.language
class Person(models.Model):
name = models.CharField(
max_length=100,
help_text='Enter a name (e.g. Harry Virani)',
validators=[MinLengthValidator(2, "It must be greater than 1 character")]
)
picture = models.BinaryField(null=True, blank=True, editable=True)
content_type = models.CharField(max_length=256, null=True, blank=True,
help_text='The MIMEType of the file')
profession = models.CharField(
max_length=100,
validators=[MinLengthValidator(2, "It must be greater than 1 character")]
)
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, default='')
address = models.CharField(max_length=256)
email = models.EmailField(max_length = 254)
phone = models.CharField(
max_length=15,
help_text='Enter a phone number like this (e.g. +91000000000)',
validators=[MinLengthValidator(10, "It must be greater than 10 character")] )
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
facebook = models.URLField(null=True, blank=True, max_length=200,
help_text='enter your facebook URL' )
instagram = models.URLField(null=True, blank=True, max_length=200,
help_text='enter your instagram link URL' )
linkedin = models.URLField(null=True, blank=True, max_length=200,
help_text='enter your Linked link URL' )
skill = models.ManyToManyField(Skills, related_name='skills', default=1)
language = models.ManyToManyField(Languages, related_name='languages', default=1)
edu = models.ManyToManyField(Education, default=1,related_name='edu' )
work = models.ManyToManyField(Workexperience,default=1, blank=True, related_name='works')
# Shows up in the admin list
def __str__(self):
return self.name
views.py
I want to save it in another class which is for creating skill & other models.
class PersonCreateView(LoginRequiredMixin, View):
template_name = 'MYP/form.html'
success_url = 'MYP:myp_create_info'
def get(self, request, pk=None):
personform = PersonForm()
ctx = { 'personform': personform}
return render(request, self.template_name, ctx)
def post(self, request, pk=None) :
# if 'personform' in request.POST:
personform = PersonForm(request.POST, request.FILES or None)
if not personform.is_valid():
ctx = {'personform': personform}
return render(request, self.template_name, ctx)
pform = personform.save(commit=False)
#adding onwer
pform.owner = self.request.user
pform.save()
return redirect(self.success_url, pform.id)
class InfoCreateView(LoginRequiredMixin, View):
template_name = 'MYP/form2.html'
success_url = reverse_lazy('MYP:all')
def get(self, request, pk):
person = get_object_or_404(Person,id=pk)
skill= SkillsForm()
skill_list = Skills.objects.filter(person=person)
ctx = { 'skill':skill, 'skill_list':skill_list }
return render(request, self.template_name, ctx)
def post(self, request, pk):
if 'skill' in request.POST:
skill = SkillsForm(request.POST or None)
if not skill.is_valid() :
ctx = { 'skill':skill}
return render(request, self.template_name, ctx)
person = get_object_or_404(Person,id=pk)
print(person)
skill = Skills(skill=request.POST['skill'], person=person)
skill.save()
print(skill.person)
return redirect('MYP:myp_create_info', pk=pk)
forms.py
class PersonForm(forms.ModelForm):
max_upload_limit = 2 * 1024 * 1024
max_upload_limit_text = naturalsize(max_upload_limit)
# Call this 'picture' so it gets copied from the form to the in-memory model
# It will not be the "bytes", it will be the "InMemoryUploadedFile"
# because we need to pull out things like content_type
picture = forms.FileField(required=False, label='File to Upload <= '+max_upload_limit_text)
upload_field_name = 'picture'
# Hint: this will need to be changed for use in the ads application :)
class Meta:
model = Person
fields = ['name', 'profession', 'picture', 'address', 'email', 'phone','facebook','linkedin','instagram'] # Picture is manual
# Validate the size of the picture
def clean(self) :
cleaned_data = super().clean()
pic = cleaned_data.get('picture')
if pic is None : return
if len(pic) > self.max_upload_limit:
self.add_error('picture', "File must be < "+self.max_upload_limit_text+" bytes")
# Convert uploaded File object to a picture
def save(self, commit=True) :
instance = super(PersonForm, self).save(commit=False)
# We only need to adjust picture if it is a freshly uploaded file
f = instance.picture # Make a copy
if isinstance(f, InMemoryUploadedFile): # Extract data from the form to the model
bytearr = f.read();
instance.content_type = f.content_type
instance.picture = bytearr # Overwrite with the actual image data
if commit:
instance.save()
return instance
class WorkexperienceForm(forms.ModelForm):
class Meta:
model = Workexperience
fields = ['work']
class EducationForm(forms.ModelForm):
class Meta:
model = Education
fields = ['school','college']
class SkillsForm(forms.ModelForm):
class Meta:
model = Skills
fields = ['skill']
class LanguagesForm(forms.ModelForm):
class Meta:
model = Languages
fields = ['language']
Ignore the rest of the code it is just for image handling....
This is what I want to do but I know it is the wrong format
I want to just add id for everything later.
In my opinion, your models are messed up. Here is how I would have write them :
class WorkExperience(models.Model):
work = models.CharField(
blank=True,
max_length=256,
help_text='eg: Juniorengineer: at L&T'
)
def __str__(self):
return self.work
class Education(models.Model):
school = models.CharField(max_length=200)
college = models.CharField(blank=True, max_length=200)
def __str__(self):
return self.school
class Skill(models.Model):
name = models.CharField(
max_length=256,
help_text='Add a skill name (eg: Programming)'
)
def __str__(self):
return self.name
class Language(models.Model):
name = models.CharField(
max_length=256,
help_text='Add a language name (eg: Gujarati)'
)
def __str__(self):
return self.name
class Person(models.Model):
name = models.CharField(
max_length=100,
help_text='Enter a name (e.g. Harry Virani)',
validators=[MinLengthValidator(2, "It must be greater than 1 character")]
)
# [...Other fields...]
skills = models.ManyToManyField(Skill, related_name='persons', blank=True)
languages = models.ManyToManyField(Language, related_name='persons', blank=True)
educations = models.ManyToManyField(Education, related_name='persons', blank=True)
work_experiences = models.ManyToManyField(WorkExperience, related_name='persons', blank=True)
def __str__(self):
return self.name
Then I need to see your forms.py to better understand how you handle it in your view.
I have a trip model, and the form asks for a outbound flight and an inbound flight, that are both ForeignKeys.
How can I save the inbound flight as None, if no flight is selected and actually allow this form field to be empty.
This is my form:
class NewTrip(ModelForm):
def __init__(self, *args, **kwargs):
super(NewTrip, self).__init__(*args, **kwargs)
self.fields['trip_id'].widget = TextInput(attrs={'class': 'form-control'})
self.fields['destination'].widget = TextInput(attrs={'class': 'form-control'})
self.fields['client'].queryset = Clients.objects.all()
class Meta:
model = Trip
fields = ('trip_id', 'destination', 'client', 'out_flight', 'hotel', 'in_flight')
And this is my model:
class Trip(models.Model):
trip_id = models.CharField(max_length=20, verbose_name="Ref. Viagem")
destination = models.CharField(max_length=200, null=True, verbose_name='Destino')
client = models.ForeignKey(Clients, null=True, on_delete=models.CASCADE, verbose_name="Cliente")
out_flight = models.ForeignKey(Flight, related_name="outbound_flight" ,null=True, on_delete=models.SET_NULL, verbose_name="Voo Ida")
hotel = models.ForeignKey(Hotels, null=True, on_delete=models.SET_NULL, verbose_name="Hotel")
in_flight = models.ForeignKey (Flight, related_name="inbound_flight", null=True, on_delete=models.SET_NULL, verbose_name="Voo Regresso")
And this is the view:
def newtrip(request):
if request.method == 'POST':
form = NewTrip(request.POST)
if form.is_valid():
form.save()
return redirect('trips')
else:
form = NewTrip()
return render(request, 'backend/new_trip.html', {'form': form})
Add blank=True to your in_flight and out_flight
in_flight = models.ForeignKey(..., blank=True)
out_flight = models.ForeignKey(..., blank=True)