Поле 'id' ожидало число, но получило 'std1', как мне получить идентификатор ForeignKey поля модели для использования в форме Django? - PullRequest
0 голосов
/ 27 мая 2020

У меня есть модель Detail, которая имеет ForeignKey модели User по умолчанию Django. Я создал форму для ввода данных от пользователя и обновления полей модели Detail, если они существуют, в противном случае создайте новую деталь.

Для этого я фильтрую Detail.objects.all() в имени пользователя. который был выбран в форме во Front-End. Теперь мне нужен идентификатор имени пользователя, которое было выбрано для обновления модели Detail. Как я могу получить удостоверение личности? Если я просто передам имя пользователя, появится Field 'id' expected a number but got 'std1'.

My models.py:

class Detail(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, limit_choices_to={'is_superuser': False, 'is_staff': False}, verbose_name="Select a Student")
    subject = models.CharField(max_length=50, verbose_name='Subject Name', help_text='Write the name of the subject.')
    skype_session_attendance = models.FloatField(validators=[MinValueValidator(0), MaxValueValidator(20)], verbose_name="Skype Session Attendances (of this subject, in numbers)", help_text="Enter the numbers of skype sessions of this subject, the student attended out of 20.")
    internal_course_marks = models.FloatField(validators=[MinValueValidator(0), MaxValueValidator(40)], verbose_name="Internal Course Marks (of this subject, in numbers)", help_text="Enter the total internal course marks of this subject, the student obtained out of 40.")
    programming_lab_activity = models.FloatField(validators=[MinValueValidator(0), MaxValueValidator(25)], verbose_name="Programming Lab Activities (of this subject, in numbers)", help_text="Enter the total numbers of programming lab activities of this subject, the student participated in, out of 25.")
    mid_term_marks = models.FloatField(validators=[MinValueValidator(0), MaxValueValidator(45)], verbose_name="Mid_Term Marks (of this subject, in numbers)", help_text="Enter the total mid-term marks of this subject, the student obtained out of 45.")
    final_term_marks = models.FloatField(validators=[MinValueValidator(0), MaxValueValidator(90)], verbose_name="Final_Term Marks (of this subject, in numbers)", help_text="Enter the total final-term marks of this subject, the student obtained out of 90.")

    def __str__(self):
        return f'{self.user.username}-{self.subject}'

    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)

My forms.py:

class UpdateStudentDetailsForm(forms.Form):
    stds = forms.CharField(widget=forms.Select(choices=STUDENTS_LIST), label='Select a Student')
    subject = forms.CharField(max_length=50)
    skype_session_attendance = forms.FloatField(min_value=0, max_value=20, label="Skype Session Attendances (of this subject, in numbers)", help_text="Enter the numbers of skype sessions of this subject, the student attended out of 20.")
    internal_course_marks = forms.FloatField(min_value=0, max_value=40, label="Internal Course Marks (of this subject, in numbers)", help_text="Enter the total internal course marks of this subject, the student obtained out of 40.")
    programming_lab_activity = forms.FloatField(min_value=0, max_value=25, label="Programming Lab Activities (of this subject, in numbers)", help_text="Enter the total numbers of programming lab activities of this subject, the student participated in, out of 25.")
    mid_term_marks = forms.FloatField(min_value=0, max_value=45, label="Mid_Term Marks (of this subject, in numbers)", help_text="Enter the total mid-term marks of this subject, the student obtained out of 45.")
    final_term_marks = forms.FloatField(min_value=0, max_value=90, label="Final_Term Marks (of this subject, in numbers)", help_text="Enter the total final-term marks of this subject, the student obtained out of 90.")
    print(stds)
    class Meta:
        fields = ['stds', 'subject', 'skype_session_attendance', 'internal_course_marks', 'programming_lab_activity', 'mid_term_marks', 'final_term_marks']

My views.py :

def updateStudentDetails(request):
    if request.method == 'POST':
        std_form = UpdateStudentDetailsForm(request.POST)

        if std_form.is_valid():
            details = std_form.cleaned_data
            usr = details['stds']

            old_details = Detail.objects.get(user=usr)      # HERE I NEED TO PUT ID INSTEAD OF 'usr'
            old_details.subject = details['subject']
            old_details.skype_session_attendance = details['skype_session_attendance']
            old_details.internal_course_marks = details['internal_course_marks']
            old_details.programming_lab_activity = details['programming_lab_activity']
            old_details.mid_term_marks = details['mid_term_marks']
            old_details.final_term_marks = details['final_term_marks']
            old_details.save()

            messages.success(request, 'Success! Academic Record/Details of ' + usr.first_name + usr.last_name + '(' + usr.username + ')' ' has been updated.')

            return redirect('update_student_details')
    else:
        std_form = UpdateStudentDetailsForm()

    return render(request, 'users/update_student_details.html', {'std_form': std_form})

1 Ответ

0 голосов
/ 27 мая 2020

Думаю, с точки зрения дизайна у него есть немного fl aws. Как и здесь, у пользователя может быть несколько объектов Detail, поскольку это отношение ForeignKey. Поэтому вызов old_details = Detail.objects.get(user=usr) вызовет ошибку, если у вас есть несколько экземпляров User. Теперь вы можете изменить его на отношение OneToOne, чтобы избежать этой проблемы:

class Detail(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, limit_choices_to={'is_superuser': False, 'is_staff': False}, verbose_name="Select a Student")

Вместо формы используйте forms.ModelForm. Вы можете попробовать вот так:

class UpdateStudentDetailsForm(forms.Form):
    class Meta:
        model = Details
        exclude = 'user'

И вместо получения формы данных stds я бы рекомендовал использовать URL-адрес для управления ею. Например:

# view
def updateStudentDetails(request, user_id):  # Please use snake_case as per PEP-8 Standards
    user = get_object_or_404(User, user_id)
    if request.method == 'POST':
        std_form = UpdateStudentDetailsForm(request.POST, instance=user.detail)
        if std_form.is_valid():
            std_form.save()
            # redirect
    else:
       std_form = UpdateStudentDetailsForm(instance=user.detail) 
    return render(request, 'users/update_student_details.html', {'std_form': std_form})

# url:
path('student/update/<int:user_id>/', updateStudentDetails, name="update_student_detail"),

Обновление

Если вы хотите иметь отношение «один ко многим» между объектом User и Detail, я бы рекомендовал получать объекты Detail с помощью pk.

Если вы настаиваете на раскрывающемся списке для выбора учащегося, используйте другую форму для перенаправления на эту updateStudentDetails страницу, например:

# form

Class StudentDetailChoiceForm(forms.Form):
    student = forms.ModelChoiceField(queryset=Detail.objects.all(), label="Choose a student")

# view

def redirect_to_student_update(request):
    form = StudentDetailChoiceForm(request.GET or request.POST)
    if form.is_valid():
        return redirect('update_student_detail', pk=form.cleaned_data['student'].pk)

И обновите вид updateStudentDetails :

def updateStudentDetails(request, pk):  # Please use snake_case as per PEP-8 Standards
    detail = get_object_or_404(Detail, pk)
    if request.method == 'POST':
        std_form = UpdateStudentDetailsForm(request.POST, instance=detail)

Кстати, вы можете использовать ModelChoiceField с существующей реализацией, например:

class UpdateStudentDetailsForm(forms.Form):
    stds = forms.ModelChoiceField(queryset=Detail.objects.all(), label="Choose a student")

И остальная часть вашей реализации должна работать, но она не будет чистым решением, поскольку вы не будете использовать принцип DRY, и вы получаете данные из формы вручную et c, где с ModelForm начальные значения будут видны в вашем шаблоне, меньше кодов и Django сам позаботится об обновлении.

...