ChillieCode
ChillieCode

Reputation: 139

How to point django form to pk?

I am trying to make a form that is dynamically selected by a DetailView object.

I want to click the DetailView link and be taken to a form whose primary key is the same as the primary key from my detail view. When I attempt to do this I get an error. How can I do this? Is their a prebuilt library that will assist me?

My Model:

'''

 class MemberStudent(models.Model):
    instructor = models.ForeignKey(Teachers, on_delete=models.CASCADE)
    name = models.CharField(max_length=50, default="Doe")
    age = models.IntegerField(default=99)


 def __str__(self):
      return self.name

 def get_absolute_url(self):
      return reverse('student_detail', args=[str(self.id)])

class BehaviorGrade(models.Model):
   SEVERITY = [
    ('Bad','Bad Behavior'),
    ('Good','Good Behavior'),
    ('Danger','Dangerous'),
]

LETTER_GRADE = [
    ('A','A'),
    ('B','B'),
    ('F','F'),
]

studentName = models.ForeignKey(MemberStudent,      on_delete=models.CASCADE) #need a link to student name
eventGrade = models.CharField(max_length=1, choices=LETTER_GRADE)
eventSeverity = models.CharField(max_length=15, choices=SEVERITY)
eventTitle = models.CharField(max_length=15)
eventDescription = models.TextField()

def __str__(self):
    return self.eventTitle

'''

My Views:

'''

class StudentDetailView(FormMixin,DetailView):
   model = MemberStudent
   template_name = 'student_detail.html'
   form_class = BehaviorForm

def get_success_url(self):
    return reverse('student_detail', kwargs={'pk':self.object.pk})



def post(self, request, *args, **kwargs):
   
    self.object = self.get_object()
    form = self.get_form()
    if form.is_valid():
        form.save()
        return self.form_valid(form)
    else:
        return self.form_invalid(form)

def form_valid(self, form):
    return super().form_valid(form)

'''

my forms.py: '''

class BehaviorForm(ModelForm):
class Meta:
    model = BehaviorGrade
    fields = ['eventGrade',
              'eventSeverity','eventTitle',
              'eventDescription']

'''

my url:

'''

 path('students/<int:pk>', StudentDetailView.as_view(), name='student_detail'),

'''

my htmltemplate(its a detailview with a form below on the same page): '''

 {{ object.id }}
 {{ object.name }}
 {{ object.age }}

 {{ object.instructor }}



  <form action="{% url 'student_detail' object.id %}" method="POST">
  {{ form }}
  {% csrf_token %}
<input type="submit" value="REVIEW">

  </form> 

'''

error message when form submitted:

"IntegrityError at /student/students/1

NOT NULL constraint failed: Students_behaviorgrade.studentName_id"

The form also is sent without the PK I have requested in my form code.

the django error log shows the PK is never sent here is the log message on a test of dummy data:

params [None, 'A', 'Bad', 'asdf', 'asdf']

Upvotes: 0

Views: 314

Answers (2)

ChillieCode
ChillieCode

Reputation: 139

The solution was to to call the primary key in the model method. Then to save to the correct model object I called .pk on my object. I'm cannot elegantly explain this solution however upon testing several different scenarios it works.

'''

def post(self, request, *args, **kwargs):
    self.object = self.get_object()
    form = self.get_form()
    if form.is_valid():
        behavior_grade = form.save(commit=False)
        behavior_grade.studentName = self.object #passes unamed form field
        behavior_grade.studentName.pk = form.save(commit=True) #calls key 
        return self.form_valid(form)
    else:
        return self.form_invalid(form)

'''

Upvotes: 0

Benbb96
Benbb96

Reputation: 2273

That's because you have to manually set the member student id on the behavior garde.

You can do it like this in the post function of your view :

def post(self, request, *args, **kwargs):
    self.object = self.get_object()
    form = self.get_form()
    if form.is_valid():
        behavior_grade = form.save(commit=False)
        behavior_grade.studentName = self.object
        return self.form_valid(form)
    else:
        return self.form_invalid(form)

You can also take a look at this method to use the form_valid function to do it :

## Include the instance object before saving
def form_valid(self, form):
    form.instance.studentName = self.object
    return super().form_valid(form)

Upvotes: 1

Related Questions