0

I am not that good at queries, so I need some help. I have a Course model, and a TeacherData model. Each teacher has its own courses. But when a teacher makes an account I use a Teacher model. And if teacher_ID column from TeacherData doesn't match the one entered by the user, the account cannot be created. Now, in my form I need to show Courses for each teacher, so that a Lecture instance can be created. I was thinking to use teacher_ID as bridge connecting Teacher model with TeacherData model and then I would be able to show the courses that only a specific teacher has. This is what I tried, but can't figure out:

class Teacher(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
    name = models.CharField(max_length=30, null=True, blank=True, default=None)
    surname = models.CharField(max_length=50, null=True, blank=True, default=None)
    email = models.EmailField(unique=True, null=True, blank=True, default=None)
    teacher_ID = models.CharField(unique=True, max_length=14,
                                  validators=[RegexValidator(regex='^.{14}$',
                                                             message='The ID needs to be 14 characters long.')],
                                  null=True, blank=True, default=None)
                                  

class Lecture(models.Model):
    LECTURE_CHOICES = (
        ('Courses', 'Courses'),
        ('Seminars', 'Seminars'),
    )
    course = models.ForeignKey('Course', on_delete=models.CASCADE, default='', related_name='lectures',)
    lecture_category = models.CharField(max_length=10, choices=LECTURE_CHOICES, default='Courses',)
    lecture_title = models.CharField(max_length=100, blank=True, null=True)
    content = models.TextField(blank=False, default=None)


class Course(models.Model):
    study_programme = models.ForeignKey('StudyProgramme', on_delete=models.CASCADE, default='')
    name = models.CharField(max_length=50, unique=True)
    ects = models.PositiveSmallIntegerField(validators=[MaxValueValidator(99)])
    description = models.TextField()
    year = models.PositiveSmallIntegerField(validators=[MaxValueValidator(99)])
    semester = models.IntegerField(choices=((1, "1"),
                                            (2, "2"),
                                            ), default=None)
    teacher1 = models.ForeignKey('TeacherData', on_delete=models.CASCADE, default=None,
                                 verbose_name="Course Teacher", related_name='%(class)s_course_teacher')
    teacher2 = models.ForeignKey('TeacherData', on_delete=models.CASCADE, default=None, null=True,
                                 verbose_name="Seminar Teacher", related_name='%(class)s_seminar_teacher')

class TeacherData(models.Model):
    name = models.CharField(max_length=30)
    surname = models.CharField(max_length=50)
    teacher_ID = models.CharField(unique=True, max_length=14)
    notes = models.CharField(max_length=255, default=None, blank=True)
 Run code snippetExpand snippet
class LectureForm(forms.ModelForm):
    lecture_title = forms.CharField(max_length=100, required=True)
    course = forms.ModelChoiceField(initial=Course.objects.first(), queryset=Course.objects.filter(
        Q(teacher1__surname__in=[t.surname for t in TeacherData.objects.filter(
            Q(teacher_ID__iexact=[x.teacher_ID for x in Teacher.objects.all()]))])))

    class Meta:
        model = Lecture
        fields = ('course', 'lecture_category', 'lecture_title', 'content')

The expected behavior is when teacher is logged in, they would able to add a new lecture only for courses that they teach. I can achieve roughly the same effect by doing the following in a template

                {% for data in teacher_data %}
                    {% if data.teacher_ID == user.teacher.teacher_ID %}
                        {% for course in courses %}
                            {% if course.teacher1 == data or course.teacher2 == data %}
                                 <li>
                                    <a href="{% url 'courses:courses' slug=course.slug %}">{{ course.name }}</a>
                                </li>
                            {% endif %}
                        {% endfor %}
                    {% endif %}
                {% endfor %}
  • 2
    Why have a `Teacher` model and a `TeacherData` model? Further, why not make `TeacherData` a OneToOne relation? Also the relationship between `Course` and `Teacher` should probably be an m2m relationship. I think some better organization of the models will help make your queries much easier. – sytech Feb 23 '18 at 16:12
  • This has nothing to do with my question. I have my reasons to keep my models organised like this. –  Feb 23 '18 at 16:16
  • 1
    @DannM this has a lot to do with your question actually. A proper relational model makes the code __much__ more simple, readable and maintainable and avoids highly inefficient queries. – bruno desthuilliers Feb 23 '18 at 16:25
  • You don't know what else I got in my project and again, I know why I keep my models like this. I just need a solution, which is not complicated but I just don't have the knowledge for it. –  Feb 23 '18 at 16:30
  • I **strongly** recommend you consider taking some time to really think if that's genuinely the case... At any rate, I'm not sure it's clear what you're trying to accomplish. The way you've written your queryset, it appears it would be equivalent to simply `Course.objects.filter(teacher1__isnull=False, teacher1__surname__isnull=False)`. What do you want the queryset to contain? which courses should be filtered? – sytech Feb 23 '18 at 16:41
  • True. This really is the first query that I did haha. For each teacher, when teacher is logged, he would able to add a new lecture only for courses that he teaches. I managed to recreate that behavior just by simply showing courses in template with this code: https://pastebin.com/AwMwEDtv –  Feb 23 '18 at 16:49
  • The problem you have is that you'd need an instance of a teacher to properly filter against. You wouldn't have such an instance until the actual request for the form is made. What you can do is make the default queryset `Course.objects.none()` then in your view, modify the forms queryset like `form.fields['course'].queryset = Course.objects.filter(Q(teacher1=the_teacher) | Q(teacher2=the_teacher))` where `the_teacher` is a `TeacherData` instance you discern from the request information, e.g. something like `TeacherData.objects.get(user=request.user)` – sytech Feb 23 '18 at 17:15
  • Possible duplicate of [How do I filter ForeignKey choices in a Django ModelForm?](https://stackoverflow.com/questions/291945/how-do-i-filter-foreignkey-choices-in-a-django-modelform) – sytech Feb 23 '18 at 17:19
  • It's a diferent question.. Anyway, I did this: https://pastebin.com/4cHcHFm9 but no courses are shown.. –  Feb 23 '18 at 17:37
  • It's the same question, essentially. What I have there is just an example. You'd have to get it working with your particular models/fields -- Note that your `TeacherData` model does not have a `user` field. Also note that this needs to be done when the form is created and presented to the user, not just after submission. You could probably benefit a great deal by utilizing django's generic class-based views, too. – sytech Feb 23 '18 at 17:59
  • This seems hard for me to understand. I'm just a beginner as you probably noticed. Could you provide some code in this case ? –  Feb 23 '18 at 18:15

0 Answers0