How can I create multiple related objects inside a view with cleaned data from two Django forms on the same page - django-models

I have 4 related Django Models ModifiedUser and Profile defined as follows . I am trying to create the person responsible for the activity,through a person model form. Through a person profile model form I am trying to add their profile details which includes the related person,country etc. Using these details I want to create a second person, called related user. Then I want to assign the two people to the activities via their Roles.
Models
'''
Class ModifiedUser:
email = models.EmailField(
max_length=255,blank=True,null=True,unique=True)
...
Class Profile:
modified_user = models.ForeignKey(ModifiedUser)
related_user = models.EmailField(
max_length=255,blank=True,null=True)
...
class Activity:
person = models.ManyToManyField(Profile,related_query_name='actor',related_name=' person', through='RoleAssignment')
class RoleAssignment:
person = models.ForeignKey(Profiles,on_delete=CASCADE,related_name="role")
feedback = models.ForeignKey(Activity,on_delete=CASCADE)
...
'''
Forms:
'''
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = '__all__'
class ModifiedUserForm(forms.ModelForm):
class Meta:
model = ModifiedUser
fields = '__all__'
'''
View
'''
from profiles.models import Profile, ModifiedUser,Activity
from .forms import ResponsibleForm, ModifiedUser
def add_activity_owner(request):
activity = Activity.objects.create(initiatedby=currentuser,updatedby=currentuser)
if request.method == 'POST':
responsibleform = ResponsibleForm(request.POST, request.FILES)
profileform = ProfileForm(request.POST, request.FILES)
if all([receiverform.is_valid(), detailform.is_valid()]):
owner_firstname =responsibleform .cleaned_data['Phone']
owner_lastname = responsibleform .cleaned_data['Address']
owner_email = responsibleform .cleaned_data['email']
relatedperson_email= profileform.cleaned_data['related_user'],
country = profileform.cleaned_data['country'],
gender = profileform.cleaned_data['gender'],
relatedperson,person_created = ModifiedUser.objects.get_or_create(email=relatedperson_email,FirstName=NULL,LastName=NULL)
owner,owner_created=Profiles.objects.get_or_create(email=owner_email,FirstName=owner_firstname,Lastame=owner_lastname)
owner_profile ,owner_created= Profiles.objects.get_or_create(user=owner,
related_user= relatedperson_email,
country = country,
gender = gender,
owner_role = RoleAssignment.objects.create(activity=activity,person=owner,role=role['owner'])
related_person_role = RoleAssignment.objects.create(activity=activity,person=relatedperson,role=role['actor'])
context['relateduser']=relateduser
context['owner']=owner
context['owner_role']=owner_role
return redirect(selectroles,activity)
else:
responsibleform = GiverForm()
profileform = UserProfileUpdateForm()
profileform':profileform})
return render(request,'addowner.html',context)
'''

Related

Using Django formset displaying related names in template

I am trying to display the state values for each country name in Django app. To save the user response, I am using Django generic CreateView. My models look something like this:
class Question(model.Models):
ques_id = models.AutoField(primary_key=True)
country = models.ForeignKey(Country)
state = models.CharField(max_length=...)
class Test(model.Models):
test = models.AutoField(primary_key=True, )
test_num = models.CharField(max_length=6, )
class Response(model.Models):
response = models.AutoField(primary_key=True)
test_id = models.ForeignKey(Test, related_name='test', )
ques_offered = models.ForeignKey(Question, related_name='choice',
ans_submitted = models.CharField(max_length=240,
To display the available choices for field state for each country value (in the db), I am looping through Django management form for the formset in my template. However, I am unable to get to the values of field state instead I am getting the country values.
Additional info:
The views that I am using to achieve this:
class ResponseCreateView(CreateView):
template_name = ...
model = Test
form_class = # Form_name
def get_context_data(self, **kwargs):
data = super(ResponseCreateView, self).get_context_data(**kwargs)
if self.request.POST:
data['get_response'] = responseFormset(self.request.POST, self.request.FILES)
else:
data['get_response'] = responseFormset()
def form_valid(self, form):
context = self.get_context_data()
get_response = context['get_response']
with transaction.atomic():
if get_response.is_valid():
self.object = form.save()
get_response.instance = self.object
get_response.save()
return redirect('...')
else:
context.update({'get_response': get_response,
})
return self.render_to_response(context)
return super(ResponseCreateView, self).form_valid(form)

Uploading data to user's page in Django using Forms

I'm trying to code the page so that every user has its userpage where they can add their own info ( in this case YCD data). Now I'm trying to code the add button, with which user will be able to add a note to its personal page.
def add_YCD(request):
current_user = request.user
current_profile = Profile.objects.get(user_id = current_user.id)
if request.method == "POST":
if current_user.is_authenticated:
YCD_form = YCDForm(request.POST, instance = current_profile)
if YCD_form.is_valid():
YCD_form.save()
messages.success(request,('Your profile was successfully updated!'))
else:
messages.error(request,('Unable to complete request'))
return redirect("main:homepage")
YCD_form = YCDForm(instance = current_profile)
return render(request = request,
template_name = "main/add_YCD.html",
context = {"YCD_form": YCD_form,
"user": request.user,})
The code works without instance = current_profile, it just saves the note to database but doesn't display it on the userpage. I've also tried using instance = request.user.profile.
But it doesn't work at all.
Here are the Models themselves:
class Yield_Curve_Data(models.Model):
b1 = models.BigIntegerField()
b2 = models.BigIntegerField()
b3 = models.BigIntegerField()
tau = models.BigIntegerField()
Date = models.DateTimeField('date published', default = datetime.now)
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
yield_curve_data = models.ManyToManyField(Yield_Curve_Data, null = True)
#receiver(post_save, sender = User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender = User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
And here's the code for forms:
class YCDForm(forms.ModelForm):
class Meta:
model = Yield_Curve_Data
fields =('b1', 'b2', 'b3', 'tau',)
Is there another way to specify the user itself or o I need to change the code completely?
Thanks

How check UniqueConstraint in Django with CreateView and custom forms if field set in view?

I do:
I define UniqueConstraint (also try with 'unique_together') in model:
class Project(models.Model):
class Meta:
constraints = [
models.UniqueConstraint(
fields=['company', 'name'], name="unique_project_name_in_company"
)
]
name = models.CharField(blank=False, max_length=256)
company = models.ForeignKey(
Company,
on_delete=models.CASCADE
)
I set company in form_valid in view (I think it's reason of my problem):
class ProjectCreateView(LoginRequiredMixin, generic.CreateView):
model = Project
form_class = ProjectForm
def form_valid(self, form):
form.instance.company = self.request.user.company
return super().form_valid(form)
I try define message for 'unique_project_name_in_company' in form:
class ProjectForm(forms.ModelForm):
model = Project
class Meta:
model = Project
fields = ['name']
error_messages = {
NON_FIELD_ERRORS: {
'unique_project_name_in_company': "Name isn't unique!",
}
}
Unexpected behavior
If I submit form with non-unique pair (inputed non-unique name) I want get my custom error_message but I get:
500 IntegrityError UNIQUE constraint failed: company_id, name

how to filter foreign key in django form without passing foreign key value?

I have created two models in my django project AddStudent and Fee Entry as shown below.
models.py
class AddStudent(models.Model):
enrollment_no = models.BigIntegerField(primary_key=True)
student_name = models.CharField(max_length=500,null=True)
gender = models.CharField(max_length=1,choices=GENDER_CHOICES)
course = models.ForeignKey(CourseMaster, on_delete=models.DO_NOTHING, null=True)
category= models.ForeignKey(CatMaster, on_delete=models.DO_NOTHING, null=True)
admission_year = models.IntegerField(('year'), choices=YEAR_CHOICES, default=datetime.datetime.now().year)
college = models.ForeignKey(CollegeMaster, on_delete=models.DO_NOTHING, null=True)
branch = models.ForeignKey(BranchMaster,on_delete=models.DO_NOTHING, null=True)
current_semester = models.IntegerField(null=True)
address = models.CharField(max_length=1000,null=True)
city = models.CharField(max_length=100,null=True)
district = models.CharField(max_length=100,null=True)
state = models.CharField(max_length=100,null=True)
student_contact = models.BigIntegerField()
parent_contact = models.BigIntegerField()
def get_absolute_url(self):
return reverse('add_student:index')
def __str__(self):
return str(self.enrollment_no) + ' - ' + self.student_name
class FeeEntry(models.Model):
student = models.ForeignKey(AddStudent,on_delete=models.DO_NOTHING)
fee_detail = models.ForeignKey(FeeMaster,on_delete=models.DO_NOTHING)
fee_sem = models.IntegerField(null=True)
payment_date = models.DateField(("Date"), default=datetime.date.today)
pay_method = models.BooleanField(choices=BOOL_CHOICES)
cheque_no = models.CharField(max_length = 100, null=True, blank=True)
bank_name = models.CharField(max_length = 200, null=True, blank=True)
def __str__(self):
return str(self.id) + ' - ' + str(self.student) + ' - ' + self.student.student_name
Now when user search particular student for example student id = 1 than student profile page will open and there is another button addfee. My problem is when user click on add fee all 500 student list is appear in dropdown list. i want to create fee for searched student only.
forms.py
from django import forms
from .models import FeeEntry, AddStudent
from bootstrap_modal_forms.mixins import PopRequestMixin, CreateUpdateAjaxMixin
class FeeForm(PopRequestMixin, CreateUpdateAjaxMixin, forms.ModelForm):
class Meta:
model = FeeEntry
fields = ['student', 'fee_detail', 'fee_sem', 'payment_date', 'pay_method','cheque_no','bank_name']
above is my forms.py file where field 'student' will generate all 500 student list. I want only selected student for example enrollment_no=1 when user is on enrollment_no 1's page.
views.py
class FeeCreateView(PassRequestMixin, SuccessMessageMixin,
generic.CreateView):
template_name = 'add_student/create_fee.html'
form_class = FeeForm
success_message = 'Success: Book was created.'
success_url = reverse_lazy('add_student:detail')
urls.py
path('create/<int:pk>', views.FeeCreateView.as_view(), name='create_fee'),
Can anyone tell me what changes are required in this code? or can you share link of similar example like this?
The FeeForm does not know which student you want to relate it with. Because of that, it is showing you a dropdown asking which student you want to assign to the FeeEntry instance.
Remove 'student' from the form and send the form to the view. when the user submits the form, use the form_valid (form.is_valid if you are using FBV) method to assign the student to the fee_entry instance.
def form_valid(self, form):
fee_entry = form.save(commit=False)
fee_entry.student = AddStudent.objects.get(id=self.kwargs['student_id'])
fee_entry.save()
Also make sure to send the student_id in the url. You can even send it as a POST parameter(check out how to retrieve parameter from a POST request) using a hidden field in the form.

How to create model objects via ModelForm ForeignKey?

I have a model for Classroom and Student as shown below
class Classroom(models.Model):
COURSE_NAME = (
('MA8', 'Math 8'),
('SC10', 'Science 10'),
('PH11', 'Physics 11'),
('PH12', 'Physics 12'),
)
BLOCK_NUMBER = (
('11', 'Block 1-1'),
('12', 'Block 1-2'),
('13', 'Block 1-3'),
('14', 'Block 1-4'),
('21', 'Block 2-1'),
('22', 'Block 2-2'),
('23', 'Block 2-3'),
('24', 'Block 2-4'),
)
class_list = models.TextField()
course_name = models.CharField(max_length=20, choices=COURSE_NAME)
course_block = models.CharField(max_length=10, choices=BLOCK_NUMBER)
class Student(models.Model):
classroom = models.ForeignKey(Classroom, on_delete=models.CASCADE)
nickname = models.CharField(default='JohnS', max_length=31)
attend = models.BooleanField(default=True)
I created a form for Classroom.class_list and TextField is where the user copy/pastes a list of names. I want to then parse the class_list and save each individual name as nickname. I first tried the following but this doesn't seem to save the Student objects.
forms.py
class ClassroomForm(ModelForm):
class Meta:
model = Classroom
fields = ['course_name', 'course_block','class_list']
views.py
class ClassroomCreateView(CreateView):
model = Classroom
form_class = ClassroomForm
def form_valid(self, form):
classroom = form.save(commit=False)
s = Student()
for line in classroom.class_list:
s.nickname = line
s.save()
classroom.save()
return super(ClassroomCreateView, self).form_valid(form)
def get_success_url(self):
return reverse('classroom:submitted')
I also tried creating StudentForm which allows a user to choose course_name and course_block (which corresponds to a particular class_list). The form or view would then create the individual Student objects and display them. I read about ModelChoiceField but I can't figure out how to implement this.
How and where do I (auto) create Students objects from a ForeignKey field?
I solved my question with the help of this answer. Here is the modified code I used for models.py. My view is just a standard CreateView from the ModelForm.
class Classroom(models.Model):
... dictionary stuff ..
class_list = models.TextField()
course_name = models.CharField(max_length=20, choices=COURSE_NAME)
course_block = models.CharField(max_length=10, choices=BLOCK_NUMBER)
group_size = models.IntegerField(default=3)
def __str__(self):
return self.get_course_block_display()
def save(self, *args, **kwargs):
super(Classroom, self).save(*args, **kwargs)
# overrides the default save function to parse the class list
studentList = []
studentList = self.class_list.split('\n')
for line in studentList:
line = line.strip('\r')
s = Student.objects.create(nickname = line, classroom = self)

Resources