CreateView does not create objects sometime

I have a basic task management app named as “weekly_reports” (app name created with django-admin).

I have a model named Reports in models.py as follows;

class Reports(models.Model):

    def get_days_of_week(year, week_number):

        first_day_of_year = datetime.date(year, 1, 1)
        first_week_day = first_day_of_year.weekday()
        days_to_add = (week_number - 1) * 7 - first_week_day
        first_day_of_week = first_day_of_year + datetime.timedelta(days=days_to_add)

        week_days = []
        for i in range(7):
            day = first_day_of_week + datetime.timedelta(days=i)
            week_days.append(day.strftime("%B%d"))

        return week_days


    year = datetime.datetime.today().year

    current_date = datetime.datetime.today()
    week_number = current_date.isocalendar()[1]

    weeks_days = []
    for i in range(week_number - 4, week_number + 5):
        days = get_days_of_week(year, i)
        weeks_days.append((days[0] + "-" + days[-1], days[0] + "-" + days[-1]))

    # All the above varibles and method are used to calculate 4 weeks before and after in a list
    week = models.CharField(max_length=30, choices=weeks_days, default=weeks_days[4])


    user = models.ForeignKey(User, on_delete=models.CASCADE)

    TAG_CHOICES = [
        ('Bitbucket / Confluence / Jira DesTech', 'Bitbucket / Confluence / Jira DesTech'),
        ('Jira DesTech', 'Jira DesTech'),
        ('OpenShift', 'OpenShift'),
        ('Altyapı', 'Altyapı'),
        ('Monitoring & Otomasyon', 'Monitoring & Otomasyon'),
        ('Diğer', 'Diğer'),
    ]

    EPIC_CHOICES = [
        ('Highlight', 'Highlight'),
        ('Lowlight', 'Lowlight'),
        ('Escalation', 'Escalation'),
        ('Information', 'Information'),
    ]


    tags = models.CharField(max_length=50, choices=TAG_CHOICES)
    epic = models.CharField(max_length=20, choices=EPIC_CHOICES)

    task = models.TextField(max_length=1000)

    status = models.BooleanField(blank=True)

    def __str__(self):
        return f"""{self.id} - {" ".join(self.task.split(" ")[:3])} - {self.user}"""

    def get_absolute_url(self):
        return reverse("report.detail", kwargs={"pk": self.pk})

    def edit(self):
        return reverse("report.update", kwargs={"pk": self.pk})

    def remove(self):
        return reverse("report.delete", kwargs={"pk": self.pk})

    def add(self):
        return reverse("report.add")

    def list(self):
        return reverse("report.list")
    

In the views.py file;

class ReportsCreateView(LoginRequiredMixin, CreateView):
    model = Reports
    form_class = ReportsForm
    success_url = "/reports"
    context_object_name = "object"

    def get_initial(self):
        return {'user': self.request.user}

I have the CreateView class as above.

I have also forms.py as follows;

class ReportsForm(forms.ModelForm):

    class Meta:
        model = Reports
        fields = ["week", "user", "tags", "epic", "task", "status"]
        help_text = {
            "week":"Task Week",
            "user":"User",
            "tags":"Task Tag",
            "epic":"Task Epic",
            "task":"Write your task definiton briefly",
            "status":"Is your task completed?"
        }
        labels = {
            "week":"week",
            "user":"user",
            "tags":"tags",
            "epic":"epic",
            "task":"task",
            "status":"status"
        }

    def get_days_of_week(year, week_number):

        first_day_of_year = datetime.date(year, 1, 1)
        first_week_day = first_day_of_year.weekday()
        days_to_add = (week_number - 1) * 7 - first_week_day
        first_day_of_week = first_day_of_year + datetime.timedelta(days=days_to_add)

        week_days = []
        for i in range(7):
            day = first_day_of_week + datetime.timedelta(days=i)
            week_days.append(day.strftime("%B%d"))

        return week_days


    year = datetime.datetime.today().year

    current_date = datetime.datetime.today()
    week_number = current_date.isocalendar()[1]

    weeks_days = []
    for i in range(week_number - 4, week_number + 5):
        days = get_days_of_week(year, i)
        weeks_days.append(days[0] +  "-" + days[-1])

    week = forms.SelectMultiple(choices=weeks_days )

    TAG_CHOICES = [
        ('Bitbucket / Confluence / Jira DesTech', 'Bitbucket / Confluence / Jira DesTech'),
        ('Jira DesTech', 'Jira DesTech'),
        ('OpenShift', 'OpenShift'),
        ('Altyapı', 'Altyapı'),
        ('Monitoring & Otomasyon', 'Monitoring & Otomasyon'),
        ('Diğer', 'Diğer'),
    ]
    tags = forms.SelectMultiple(choices=TAG_CHOICES)

    EPIC_CHOICES = [
        ('Highlight', 'Highlight'),
        ('Lowlight', 'Lowlight'),
        ('Escalation', 'Escalation'),
        ('Information', 'Information'),
    ]
    epic = forms.SelectMultiple(choices=EPIC_CHOICES)

    task = forms.CharField(max_length=1000, required=True)

    status = forms.BooleanField(initial=False)

    def __init__(self, *args, **kwargs):
        super(ReportsForm, self).__init__(*args, **kwargs)
        for i in self.Meta.fields[:-1]:

            self.fields[i].widget.attrs['class'] = 'form-control w-75'
            self.fields[i].widget.attrs['placeholder'] = i.title()
            self.fields[i].label = ''
            self.fields[i].help_text = f'<span class="form-text text-muted"><small>{self.Meta.help_text[i].title()}</small></span>'

        self.fields["status"].widget.attrs["class"] = "form-text w-25"
        self.fields["status"].widget.attrs['placeholder'] = self.Meta.fields[-1].title()
        self.fields["status"].label = 'Status'
        self.fields["status"].help_text = f'<span class="form-text text-muted"><small>{self.Meta.help_text["status"].title()}</small></span>'
        
        self.fields["user"].disabled = True

In the template for this object I have the below html code;

{% block content %}
  
    <div class="container ">
        <div class="card shadow p-3 col-6 d-flex flex-column justify-content-center">
            <form method="post" class="form w-100">
                {% csrf_token %}

                {{ form.as_p }}

                <button class="btn btn-primary" type="submit">
                    <a href="{% url 'report.list' %}" style="color: white; text-decoration: none;">Save</a>
                </button>
            </form>
        </div>
    </div>

{% endblock content %}

I can see the form in the browser, everything related to viewing objects and listing works as desired. However, I can not create Reports objects using this setup. Sometimes CreateView creates Reports sometimes does not create.

For debugging, I installed debug_toolbar and enabled “INTERCEPT_REDIRECTS”. When CreateView did not create Reports object, INTERCEPT_REDIRECTS did not intercepted the redirection. When CreateView did create Reports object, I can see the related INSERT script in the SQL tab of debug_toolbar.

I could not be able to further debug. What could be the possible reasons for CreateView failure?

There is a lot of code here and it’s hard to pinpoint the problem just by looking at it. If it was my code, and I’d no better idea, I’d start commenting out or removing things until either (a) the problem goes away (i.e. you’ve found the code that causes the problem or (b) you can’t remove any more code and still demonstrate the problem.

If you reach (a) well done, you’ve debugged it yourself!

If you reach (b) then you have a minimal example that demonstrates the problem, and you’re more likely to get useful help from strangers.

That said, all of this in your model rings an alarm for me (although it might be unrelated to this bug):

    current_date = datetime.datetime.today()
    week_number = current_date.isocalendar()[1]

    weeks_days = []
    for i in range(week_number - 4, week_number + 5):
        days = get_days_of_week(year, i)
        weeks_days.append((days[0] + "-" + days[-1], days[0] + "-" + days[-1]))

I think that code will run when the class is instantiated, not when you create each new model. So even if it’s not the cause of this bug I suspect it will cause other problems in the long run. Better to move all of that into a method, and then use that method (instead of week_days) for the week field’s choices argument.

The similar code in the body of your form should probably be handled similarly.

Thanks for your advice. Basically, all this code (said to be long) does is get a list of 4 weeks before and after current week; in total 9 weeks. It is done so that only Monday to Sunday returned for each week boundaries. It returns weeks_days as a Python list and its used as choices for a dropdown menu. The final list looks like

weeks_days = [
              ... ,
              December02-December08,
              December09-December15,
             ...
]

where December02 is Monday and December08 is Sunday.

My problem is about saving the form input fields to DB after pressing the button. Maybe listing steps through getting input from user to saving it to the DB would be useful for me to debug each step. The deepest step I could check was post_save(). I am not sure if this is the one step I should check even.

Any comment would be appreciated. Thanks!

Finally, I found that in the forms.py, status field is a type of forms.BooleanField which has to be defined with status = forms.BooleanField(initial=False, required=False).