Invite Registered Users to vote in voting app

51 Views Asked by At

I'm trying to expand the Django tutorial for a school project and make it into a more usable voting app.

What I want is to allow users to create Polls and invite other registered users by email to vote on their Poll. Only the invited users will be allowed to vote.

My models.py:

class Poll(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published', auto_now_add=True)
    is_active = models.BooleanField(default=True)
    activation_date = models.DateTimeField('Activation Date', blank=True, null=True)
    expiration_date = models.DateTimeField('Expiration Date', blank=True, null=True)
    public_key = models.CharField(max_length=30, blank=True)
    hash = models.CharField(max_length=128, blank=True)
    timestamp = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.question_text

    def was_published_recently(self):
        now = timezone.now()
        return now - datetime.timedelta(days=1) <= self.pub_date <= now
    was_published_recently.admin_order_field = 'pub_date'
    was_published_recently.boolean = True
    was_published_recently.short_description = 'Published recently?'


class Choice(models.Model):
    question = models.ForeignKey(Poll, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

    def __str__(self):
        return self.choice_text


class EligibleVoters(models.Model):
    user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
    poll = models.ForeignKey(Poll, on_delete=models.CASCADE)
    email = models.EmailField(null=True)

I have a Poll table which contains the Poll Title and other information regarding the Poll. I also created a separate Choices table (like in the tutorial) which has a ForeignKey to the Poll table and contains the poll choices. I figured that in order to invite users as eligible voters I needed a third table with ForeignKeys to the Poll and User tables. So i created one.

I should note that I'm using the build-in user model.

Here's my views.py:

class NewPoll(CreateView):
    model = Poll
    fields = ['question_text', 'is_active', 'activation_date', 'expiration_date']
    success_url = reverse_lazy('voting:index')

    def get_context_data(self, **kwargs):
        data = super().get_context_data(**kwargs)
        if self.request.POST:
            data['choices'] = ChoiceFormSet(self.request.POST)
            # data['eligible_voters_poll'] = EligibleVotersFormSetPoll(self.request.POST)
            # data['eligible_voters_user'] = EligibleVotersFormSetUser(self.request.POST)
            #data['eligible_voters'] = EligibleVotersFormSet(self.request.POST)
        else:
            data['choices'] = ChoiceFormSet()
        #     data['eligible_voters_poll'] = EligibleVotersFormSetPoll()
        #     data['eligible_voters_user'] = EligibleVotersFormSetUser()
        #    data['eligible_voters'] = EligibleVotersFormSet()
        return data

    def form_valid(self, form):
        context = self.get_context_data()
        choices = context['choices']
        # eligible_voters_poll = context['eligible_voters_poll']
        # eligible_voters_user = context['eligible_voters_user']
        #eligible_voters = context['eligible_voters']
        with transaction.atomic():
            self.object = form.save()
            if choices.is_valid():
                choices.instance = self.object
                choices.save()
            # if eligible_voters_poll.is_valid() and eligible_voters_user.is_valid():
            #     eligible_voters_poll.instance = self.object
            #     eligible_voters_poll.save()
            #     eligible_voters_user.instance = self.object
            #     eligible_voters_user.save()
            #if eligible_voters.is_valid():
            #    eligible_voters.instance = self.object
            #    eligible_voters.save()
        return super().form_valid(form)

I have commented the lines that are previous attempt into making it work. Without the commented lines the user is able to create a poll and also create choices. I'm having trouble making the invite part working though.

Here is my forms.py:

class PollForm(ModelForm):
    activation_date = forms.DateTimeField(required=False)
    expiration_date = forms.DateTimeField(required=False)

    class Meta:
        model = Poll
        fields = ['question_text', 'is_active', 'activation_date', 'expiration_date']


class ChoiceForm(ModelForm):
    class Meta:
        model = Choice
        exclude = ['votes']


ChoiceFormSet = inlineformset_factory(Poll, Choice, form=ChoiceForm, extra=1)


def form_maker(parent2):
    class EligibleVotersForm(ModelForm):
        # def __init__(self, user, poll, *args, **kwargs):
        #     self.user = user
        #     self.poll = poll
        #     super().__init__(*args, **kwargs)

        def save(self, commit=True):
            instance = super(EligibleVotersForm, self).save(commit=False)
            # instance.parent1 = parent1
            instance.parent2 = parent2
            if commit:
                instance.save()
            return instance

        class Meta:
            model = EligibleVoters
            fields = ['email']
    return EligibleVotersForm


# EligibleVotersFormSetPoll = inlineformset_factory(Poll, EligibleVoters, form=EligibleVotersForm, extra=1)
# EligibleVotersFormSetUser = inlineformset_factory(User, EligibleVoters, form=EligibleVotersForm, extra=1)
# EligibleVotersFormSet = inlineformset_factory(Poll, EligibleVoters, form=form_maker(User), extra=1)

Here I have commented out again the lines that belong to my failed attempts at making it work. The closer I got it to working is to be able to invite by any email (not just the registered ones, which is what I want) and fill the EligibleVoters table with the emails associated with the poll_id. The user_id column though remained, empty.

Here's my html file:

{% extends 'base.html' %}

{% block content %}
{% load static %}
  <h2>Poll Creation</h2>
<div class="col-md-4">
  <form action='' method="post">
    {% csrf_token %}
    {{ form.as_p }}

    <table class="table">
        {{ choices.management_form }}

        {% for form in choices.forms %}
            {% if forloop.first %}
                <thead>
                <tr>
                    {% for field in form.visible_fields %}
                        <th>{{ field.label|capfirst }}</th>
                    {% endfor %}
                </tr>
                </thead>
            {% endif %}
            <tr class="{% cycle 'row1' 'row2' %} formset_row1">
                {% for field in form.visible_fields %}
                    <td>
                        {% if forloop.first %}
                            {% for hidden in form.hidden_fields %}
                                {{ hidden }}
                            {% endfor %}
                        {% endif %}
                        {{ field.errors.as_ul }}
                        {{ field }}
                    </td>
                {% endfor %}
            </tr>
        {% endfor %}
    </table>
    <table class="table">
        {{ eligible_voters.management_form }}

        {% for form in eligible_voters.forms %}
            {% if forloop.first %}
                <thead>
                <tr>
                    {% for field in form.visible_fields %}
                        <th>{{ field.label|capfirst }}</th>
                    {% endfor %}
                </tr>
                </thead>
            {% endif %}
            <tr class="{% cycle 'row1' 'row2' %} formset_row2">
                {% for field in form.visible_fields %}
                    <td>
                        {% if forloop.first %}
                            {% for hidden in form.hidden_fields %}
                                {{ hidden }}
                            {% endfor %}
                        {% endif %}
                        {{ field.errors.as_ul }}
                        {{ field }}
                    </td>
                {% endfor %}
            </tr>
        {% endfor %}
    </table>
    <input type="submit" value="Save"/> <a href="{% url 'voting:index' %}">back to the list</a>
    </form>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="{% static 'voting/js/jquery.formset.js' %}"></script>
<script type="text/javascript">
        $('.formset_row1').formset({
            addText: 'add poll choice',
            deleteText: 'remove',
            prefix: 'choice_set'
        });
        $('.formset_row2').formset({
            addText: 'add eligible voter',
            deleteText: 'remove',
            prefix: 'eligiblevoters_set'
        });
</script>
{% endblock %}

Any ideas on how to make it work and only allow he eligible voters to vote for the polls they are invited to? I was thinking that maybe my EligibleVoters model is wrong somehow and I need a ManyToMany field somewhere??

0

There are 0 best solutions below