katcopp
katcopp

Reputation: 3

Incrementing a variable of a class based on initiation of another class python/django

My goal is to display the total number of entries in a specific contest. Initially I tried doing this within the template section by incrementing a counter for each contest as I looped through entries. My thought is that when an entry submission is created, the total_submissions for the corresponding contest should be incremented, however I'm not sure how to do it.

Model:

class Contest(models.Model):
    contest_name = models.CharField(max_length=200)
    contest_description = models.CharField(max_length=5000)
    contest_start_date = models.DateTimeField('start date')
    contest_end_date = models.DateTimeField('end date')
    submission_count = models.IntegerField(default=0)

    def __str__(self):
        return self.contest_name


class Submission(models.Model):
    contest = models.ForeignKey(Contest, on_delete=models.CASCADE)
    user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
    date_uploaded = models.DateTimeField(auto_now_add=True)
    votes = models.IntegerField(default=0)

    def __init__(self):
        #increment the submission_count variable for the corresponding contest

Other attempt by using templates:

<h1>Current Contests</h1>
<div class="row">
    {% if current_contest_list %}
        {% for contest in current_contest_list %}
            <div class="col-sm-4"><h1><a href="{% url 'contests:detail' contest.id%}">{{ contest.contest_name }}</a></h1>
                <img src="media/{{contest.display_image}}" class="img-responsive" alt="image">
                {{ contest.contest_name }}

                {% for submission in submission_list %}

                    {% if submission.contest == contest.contest_name %}
                        <P>Hi!</P>
                    {% endif %}
                    <p>{{ submission.contest }} {{ contest.contest_name }}</p>
                    {% if submission.contest == contest.contest_name %}
                        <P>Hi!</P>
                        {{ forloop.counter }}
                        {% set total_submissions = forloop.counter %}
                    {% endif %}


                {% endfor %}

    <p>Total entries: {{total_submissions}} </p>

When I did this, the total_submissions variable did not increment. What am I missing?

Upvotes: 0

Views: 59

Answers (2)

dvnguyen
dvnguyen

Reputation: 3022

As I understand, you want to increase a contest's submission count when a new submission is added. To do that, you'll need

  1. increase submission_count when a new Submission is inserted to the db
  2. decrease submission_count when a Submission is deleted

To do (1), you can override the save() method of Submission:

 def save(self, *args, **kwargs):
        if self.id is None: # To make sure this is an INSERT, not an UPDATE
                contest = Contest.objects.select_for_update().get(id=self.contest.id)
                contest.submission_count += 1
                contest.save()
                super().save(*args, **kwargs)  # Call the "real" save() method.

To do (2), you can override the delete() method:

def delete(self):
        contest = Contest.objects.select_for_update().get(id=self.contest.id)
        contest.submission_count -= 1
        contest.save()
        super().delete()

Note that this solution doesn't work if you creating or deleting submissions in bulk. See more at https://docs.djangoproject.com/en/2.1/topics/db/models/#overriding-predefined-model-methods

Personal Opinion: I wouldn't store submission count in db, unless the query to count number of submissions has noticeable impact on performance.

Upvotes: 1

little_birdie
little_birdie

Reputation: 5867

Django really discourages changing of data within templates, and they make it pretty hard to do. What you are trying to do won't work in a template.

In your template code, where is submission_list coming from? If you want to iterate over all the submissions in each contest in your contest_list, you would want to do something like:

 {% for submission in contest.submission_set.all %}

To get the count, if your list is actually a Queryset (it usually is).. then the easiest way to get a count within the template is to use count on the queryset, eg:

{{ contest.submission_set.all.count }}

This will result in another database query, but if you aren't worried about a super high volume of visitors it should be no problem.

Upvotes: 0

Related Questions