Invite Registered Users to vote in voting app - django

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"/> back to the list
</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??

Related

Customizing inlineformset choice in Django template

I've got some forms I'm trying to customize.
I render the fields manually - and it all works fine until get to a particular field (which is an InlineFormset itself). I'm trying to customize those options but can't seem to figure out how to do so.
my forms.py looks like this:
class SummativeScoreForm(forms.ModelForm):
subdomain_proficiency_level = forms.ModelChoiceField(
empty_label="Undecided",
queryset=SubdomainProficiencyLevel.objects.none(),
widget=forms.RadioSelect,
required=False,
)
def __init__(self, request, *args, **kwargs):
super(SummativeScoreForm, self).__init__(*args, **kwargs)
if self.instance:
if request.user == self.instance.summative.employee:
self.fields["subdomain_proficiency_level"].disabled = True
self.fields[
"subdomain_proficiency_level"
].queryset = SubdomainProficiencyLevel.objects.filter(
subdomain=self.instance.subdomain
)
self.fields[
"subdomain_proficiency_level"
].label = f"""
{self.instance.subdomain.character_code}:
{self.instance.subdomain.short_description}
"""
class Meta:
model = SummativeScore
fields = "__all__"
SummativeScoreInlineFormset = inlineformset_factory(
Summative,
SummativeScore,
fields=("subdomain_proficiency_level",),
can_delete=False,
extra=0,
form=SummativeScoreForm,
)
My template for summative_score_form looks like this:
<form method="post" novalidate>
{% csrf_token %}
{% include "myapp/includes/summative_score_response_formset_snippet.html" with formset=form %}
<button type="submit" class="btn btn-primary"><i class="fal fa-clipboard-check"></i> Submit Updated Scores</button>
</form>
The summative_score_response_formset_snippet looks like this:
{{ formset.management_form }}
{% for formset_form in formset.forms %}
{% if formset_form.non_field_errors %}
<ul>
{% for error in formset_form.non_field_errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
{% for hidden_field in formset_form.hidden_fields %}
{% if hidden_field.errors %}
<ul>
{% for error in hidden_field.errors %}
<li>
(Hidden field {{ hidden_field.name }}) {{ error }}
</li>
{% endfor %}
</ul>
{% endif %}
{{ hidden_field }}
{% endfor %}
{% for field in formset_form.visible_fields %}
{% if field.name == 'subdomain_proficiency_level' %}
<label class="form-check-label" for="{{ field.id_for_label }}">
{{ field.label }}
</label>
<ul id="{{ field.auto_id }}" class="form-check mt-2">
{% for choice in formset_form.subdomain_proficiency_level %}
<div class="form-check">
<!--
THIS IS THE PART I WOULD LIKE TO CUSTOMIZE:
Unsatisfactory (name) Lorum Ipsum (description)
Satisfactory (name) Lorum Ipsum (description)
Excellent (name) Lorum Ipsum (description)
CURRENTLY IT ONLY SHOWS THE NAME
-->
{{ choice }}
</div>
{% endfor %}
</ul>
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
{% else %}
{{ field }}
{% endif %}
{% endfor %}
{% endfor %}
My models look like this:
class SubdomainProficiencyLevel(CreateUpdateMixin):
"THIS IS THE 'UNSATISFACTORY' (name) 'LORUM IPSUM' (description)"
name = models.CharField(max_length=75)
description = models.TextField()
sequence = models.IntegerField()
class Meta:
ordering = ["sequence"]
verbose_name = "Subdomain Rank"
verbose_name_plural = "Subdomain Ranks"
def __str__(self):
"""
THIS IS WHAT IS 'CHOICE' IN THE FORM
I'm trying to edit this to add styles to the self.description on the form
"""
return f"{self.name}"
class SummativeScore(CreateUpdateMixin, CreateUpdateUserMixin):
summative = models.ForeignKey(Summative, on_delete=models.PROTECT)
subdomain = models.ForeignKey(Subdomain, on_delete=models.PROTECT)
subdomain_proficiency_level = models.ForeignKey(
SubdomainProficiencyLevel,
on_delete=models.PROTECT,
null=True,
blank=True,
)
class Meta:
ordering = ["subdomain__character_code"]
verbose_name = "SummativeScore"
verbose_name_plural = "SummativeScores"
def __str__(self):
"""Unicode representation of SummativeScore."""
return f"{self.subdomain_proficiency_level}"
The view is a Class Based FormView
class SummativeScoreFormView(
LoginRequiredMixin,
UserIsObserverOrObserveeMixin,
SingleObjectMixin,
FormView,
):
model = Summative
template_name = "myapp/summative_score_form.html"
pk_url_kwarg = "summative_id"
def get(self, request, *args, **kwargs):
summative_id = kwargs.pop("summative_id")
self.object = self.get_object(
queryset=Summative.objects.filter(id=summative_id)
)
return super().get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
summative_id = kwargs.pop("summative_id")
self.object = self.get_object(
queryset=Summative.objects.filter(id=summative_id)
)
return super().post(request, *args, **kwargs)
def get_form(self, form_class=None):
formset = SummativeScoreInlineFormset(
**self.get_form_kwargs(), instance=self.object
)
return formset
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs["form_kwargs"] = {"request": self.request}
return kwargs
def form_valid(self, form):
form.save()
messages.success(self.request, "Changes were saved!")
return super().form_valid(form)
def form_invalid(self, form):
return super().form_invalid(form)
def get_success_url(self):
user_id = self.kwargs["user_id"]
summative_id = self.kwargs["summative_id"]
return reverse(
"myapp:summative_detail",
kwargs={
"user_id": user_id,
"summative_id": summative_id,
},
)
As you can see in the template - I render the SubdomainProficiencyLevel objects with the template variable {{ choice }}
I have tried doing {{ choice.description }} or {{ choice.name }} <span class="bold">{{ choice.description }}</span> but then nothing displays.
I have also tried adjusting the __str__ method on the model - which changes there work, but do not render as HTML (just as a string as expected).
What is the best way to customize that in the HTML?
I ended up creating a custom radio button class (similar to the documentation)
class CustomRadioSelect(forms.RadioSelect):
def create_option(
self, name, value, label, selected, index, subindex=None, attrs=None
):
option = super().create_option(
name, value, label, selected, index, subindex, attrs
)
if value:
option["attrs"]["description"] = value.instance.description
return option
Using that in the form:
subdomain_proficiency_level = forms.ModelChoiceField(
empty_label="Undecided",
queryset=SubdomainProficiencyLevel.objects.none(),
widget=CustomRadioSelect(),
required=False,
)
Then I could access it like this in the template:
{{ choice.data.attrs.description }}

How to create a django formset or form add/edit page in order to edit several records

For one of my open source projects, I need to create ONE add/edit page in order to make possible to edit several records with one save.
The repo is an IMDB clone formed for learning purpose. A user can add her/his favorite genres in her/his profile. Then an edit page is formed to show the list of those favored genres and the movies within that genre. (A for loop here) User can add notes, watch list options and so on to those movies. (NOT a FORMSET)
However, the code doesn't work as expected. The page cannot be saved and only the first checkbox of the list can be changed.
There is no error.
NOTE:
You can install repo with dummy data.
(https://github.com/pydatageek/imdb-clone)
Then after logging in, select your favorite genres. (http://localhost:8000/users/profile/)
Then (I wish it can be solved here) you can see the movies with your selected genres. Add notes, to watch list... (http://localhost:8080/users/profile/movies2/)
# users/templates/user-movies-with_loop.html
{% extends 'base.html' %}{% load crispy_forms_tags %}
<!-- Title -->
{% block htitle %}Your movies from favorite genres{% endblock %}
{% block title %}Your movies from favorite genres{% endblock %}
{% block content %}
<div class="card card-signin">
{% include 'users/profile-menu.html' %}
<h3 class="card-title text-center my-4">Take notes for your movies <small></small></h3>
<hr class="mb-1">
<div class="card-body">
<form method="POST">
{% csrf_token %}
{% for genre in user.genres.all %}
<h2 for="genre" name="genre" value="{{ genre.id }}">{{ genre.name }}</h2>
{% for movie in genre.movies.all %}
<div class="ml-5">
<h4>{{ movie.title }}</h4>
{{ form|crispy }}
</div>
<input type="hidden" name="user" value="{{ user.id }}">
<input type="hidden" name="movie" value="{{ movie.id }}">
{% empty %}
<p class="alert alert-danger">The genre you have selected on your profile doesn't have any movies!</p>
{% endfor %}
{% empty %}
<p class="alert alert-danger">You should select genres with movies from your profile to edit here!</p>
{% endfor %}
<input class="btn btn-lg btn-primary btn-block text-uppercase" type="submit" value="Submit">
</form>
</div>
</div>
{% endblock %}
# users.forms.py
...
class UserMovieFormWithLoop(ModelForm):
genre = forms.HiddenInput(attrs={'disabled': True})
class Meta:
model = UserMovie
fields = ('user', 'movie', 'note', 'watched', 'watch_list')
widgets = {
'user': forms.HiddenInput,
'movie': forms.HiddenInput,
'watched': forms.CheckboxInput(),
}
...
# users.models.py
...
class UserMovie(models.Model):
"""
Users have notes about their favorite movies.
"""
user = models.ForeignKey(User, on_delete=models.CASCADE)
movie = models.ForeignKey('movies.Movie', default=1, on_delete=models.CASCADE)
note = models.CharField(max_length=250, null=True, blank=True)
watched = models.BooleanField(default=False, verbose_name='Have you seen before?')
watch_list = models.BooleanField(default=False, verbose_name='Add to Watch List?')
def __str__(self):
return f'{self.user.username} ({self.movie.title})'
...
# users.views.py
...
class UserMovieViewWithLoop(LoginRequiredMixin, CreateView):
model = UserMovie
template_name = 'users/user-movies-with_loop.html'
form_class = UserMovieFormWithLoop
success_message = 'your form has been submitted.'
success_url = reverse_lazy('users:user_movies2')
def form_valid(self, form):
user = self.request.user
movie_counter = Movie.objects.filter(genres__in=user.genres.all()).count()
f = form.save(commit=False)
f.user = user
for i in range(movie_counter):
f.pk = None
f.save()
return super().form_valid(form)
def get_context_data(self, **kwargs):
context = super(UserMovieViewWithLoop, self).get_context_data(**kwargs)
context['form'] = self.form_class
return context
def get_object(self):
user = self.request.user
return UserMovie.objects.get(user=user)
...

Django inlineformset will not submit

My application has two models, Recipe and RecipeIngredient, related by foreign key. Each Recipe may have many different RecipeIngredients (and different number of associated ingredients for each recipe). So using a dynamic formset to assign ingredients to a recipe seems to be the best approach.
I have a simple form that has a user enter a quantity and select a unit and ingredient from a dropdown. As a standalone form it works fine.
Unfortunately, I cannot get any formset incorporating it to submit.
I have searched many of the different formset Q&As here on StackOverflow but cannot see where the problem is. When I click 'submit', the form blinks and refreshes in place, with the entered values still in the form. No objects are created. No errors report to the console nor to the browser. The related code:
The models:
class RecipeBase(models.Model):
id = models.UUIDField(primary_key=True,default=uuid.uuid4,null=False)
name = models.CharField(max_length=128,null=False)
creation_date = models.DateField("Record creation date",auto_now_add=True)
creation_user = models.CharField("Record creation user",max_length=150)
lastupdated_date = models.DateField(auto_now=True)
lastupdated_user = models.CharField(max_length=150)
category = models.ForeignKey(RecipeCategory,on_delete=models.CASCADE,related_name='recipes')
subcategory = models.ForeignKey(RecipeSubcategory,on_delete=models.CASCADE,related_name='recipes')
def __str__(self):
return str(self.name)
class RecipeIngredient(models.Model):
id = models.UUIDField(primary_key=True,default=uuid.uuid4,null=False)
quantity = models.DecimalField(max_digits=8,decimal_places=3,null=False)
referenced_unit = models.ForeignKey(UnitDetail,on_delete=models.CASCADE)
referenced_ingredient = models.ForeignKey(Ingredient,on_delete=models.CASCADE)
parent_recipe = models.ForeignKey(RecipeBase,on_delete=models.CASCADE,related_name='ingredients')
def __str__(self):
return str(self.id)[:8]
The call to enter ingredients:
<a class='btn btn-success' href="{% url 'recipes:addingredient' pk=recipe_details.pk %}">Add Ingredients</a>
Calls the view:
class AddIngredientView(CreateView):
form_class = AddIngredientForm
model = RecipeIngredient
template_name = 'addingredientmultiple2.html'
success_url = "recipes:listrecipes"
def get_context_data(self, **kwargs):
parent_recipe_id = RecipeBase.objects.get(id=self.kwargs['pk'])
data = super(AddIngredientView, self).get_context_data(**kwargs)
if self.request.POST:
data['ingredients'] = AddIngredientFormset(self.request.POST)
data['parent_recipe_id'] = parent_recipe_id
else:
data['ingredients'] = AddIngredientFormset()
data['fixture'] = parent_recipe_id
return data
def form_valid(self, form, **kwargs):
user = self.request.user
fixture = RecipeBase.objects.get(id=self.kwargs['pk'])
context = self.get_context_data()
formset = AddIngredientFormset(self.request.POST)
if formset.is_valid():
ingredients = formset.save()
for recipeingredient in ingredients:
#recipeingredient.creation_user = str(request.user)
#recipeingredient.lastupdated_user = str(request.user)
recipeingredient.parent_recipe_id = parent_recipe_id
#recipeingredient.user = user
recipeingredient.save()
return super(AddIngredientView, self).form_valid(form)
Using form and formset:
class AddIngredientForm(forms.ModelForm):
quantity = forms.DecimalField(widget=forms.NumberInput(attrs={'data-placeholder': 0.00,'size': '8','label_tag': ''}))
referenced_unit = forms.ModelChoiceField(queryset=UnitDetail.objects.all())
referenced_ingredient = forms.ModelChoiceField(queryset=Ingredient.objects.all())
class Meta():
model = RecipeIngredient
fields = ('quantity','referenced_unit','referenced_ingredient',)
AddIngredientFormset = inlineformset_factory(RecipeBase,RecipeIngredient,form=AddIngredientForm,extra=1,can_delete=True)
And template:
{{ ingredients.media.css }}
<div class="container">
<h2>Add ingredients to {{ referring_recipe_name }}</h2>
<h4>{{ referring_recipe_id }}</h4>
</div>
<div class="col-md-4">
<form class="form-horizontal" enctype="multipart/form-data" method="post">{% csrf_token %}
<table class="table">
{{ ingredients.management_form }}
{% for form in ingredients.forms %}
{% if forloop.first %}
<thead>
<tr>
{% for field in form.visible_fields %}
<th>{{ field.label|capfirst }}</th>
{% endfor %}
</tr>
</thead>
{% endif %}
<tr class="formset_row">
{% for field in form.visible_fields %}
<td>
{# Include the hidden fields in the form #}
{% if forloop.first %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% endif %}
{{ field.errors.as_ul }}
{{ field }}
</td>
{% endfor %}
</tr>
{% endfor %}
</table>
<input class='btn btn-success' type="submit" value="Save"/> back to the list
</form>
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="{% static 'formset/jquery.formset.js' %}"></script>
<script type="text/javascript">
$('.formset_row').formset({
addText: 'ADD INGREDIENT',
deleteText: 'REMOVE',
prefix: 'ingredients'
});
</script>
{{ ingredients.media.js }}

How to Query DB using .object in Django

I have few categories. Say Electronics and Toy. and i have mutiple shops in a mall. A shop is saved with a foreign key(category). Now in the navigation bar.. i want to list stores based on their categories. Thanks in anticipation
models.py
class ShopCategories(models.Model):
category = models.CharField(max_length=50, unique=True,)
def __str__(self):
return self.category
class NewShop(models.Model):
category = models.ForeignKey(ShopCategories)
name = models.CharField(max_length=100, unique=True)
tagline = models.CharField(max_length=50, default='Enter tagline here2')
description = models.TextField(default='enter shop description')
def __str__(self):
return self.name
views.py
def basefile(request):
shop_cat = NewShop.objects.filter(category_id=1)
shop_name = NewShop.objects.filter(name=shop_cat)
return render_to_response('base.html', {'Shopname':shop_name, 'Shopcat':shop_cat})
base.html
{% for category_id in Shopcat %}
<li>{{ Shopname }}</l>
{% endfor %}
To get all store use below query.
shopcat = NewShop.objects.filter(category__category="category name")
base.html
{% for shop in shopcat %}
<li>{{ shop.name }}</l>
{% endfor %}
Try do this:
urls.py
urlpatterns = [
...
url(r'^get_shops_by_category/(?P<id_category>\d+)/$', views.get_shops_by_category, name = "get_shops_by_category"),
]
views.py
def basefile(request):
categories = ShopCategories.objects.all()
shop_name = NewShop.objects.filter(name=shop_cat)
return render_to_response('base.html', {'Shopname':shop_name, 'categories': categories})
def get_shops_by_category(request, **kwargs):
categories = ShopCategories.objects.all()
current_category = ShopCategories.objects.get(id = kwargs['id_category']
shops = NewShop.objects.filter(category = current_category)
return render_to_response('base.html', {'shops': shops, 'categories': categories, 'current_category' current_category})
base.html
...
<select>
{% for category in categories %}
{% if current_category %}
<option value="{{ category.id }}">{{ category.category }}</option>
{% else %}
<option value="{{ category.id }}" onclick="location.href = '{% url 'your_app:your_url' category.id %}'">{{ category.category }}</option>
{% endfor %}
</select>
{% if shops %}
<table>
<thead>
<tr>
<th>Shop name</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for shop in shops %}
<tr>
<td>{{ shop.name }}</td>
<td><!-- Buttons or links, ect ... --></td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
...
Thanks Guys. I know this isn't the best method but i was able to fix it this way
models.py
class ShopCategories(models.Model):
category = models.CharField(max_length=50, unique=True)
def __str__(self):
return self.category
class NewShop(models.Model):
category = models.ForeignKey(ShopCategories)
name = models.CharField(max_length=100, unique=True)
tagline = models.CharField(max_length=50, default='Enter tagline here2')
description = models.TextField(default='enter shop description')
def __str__(self):
return self.name
views.py
def basefile(request):
cat1 = NewShop.objects.filter(category_id=1)
cat2 = NewShop.objects.filter(category_id=2)
cat3 = NewShop.objects.filter(category_id=3)
cat4 = NewShop.objects.filter(category_id=4)
shop_name1 = ShopCategories.objects.filter(id=1)
shop_name2 = ShopCategories.objects.filter(id=2)
shop_name3 = ShopCategories.objects.filter(id=3)
shop_name4 = ShopCategories.objects.filter(id=4)
return render_to_response('base.html', {'Shop_cat1':cat1, 'Shop_cat2':cat2, 'Shop_cat3':cat3,
'Shop_cat4':cat4,'shop_name1':shop_name1, 'shop_name2':shop_name2,
'shop_name3':shop_name3, 'shop_name4':shop_name4})
base.html
{% for shop_name1 in shop_name1 %}
<li>
<h3> {{ shop_name1 }}</h3>
</li>
{% endfor %}
{% for Shop_cat1 in Shop_cat1 %}
<li>{{ Shop_cat1 }}</li>
{% endfor %}

Display a form and the output on the same page

This code will display the form. I can input data, submit the data and the data then displays along with the previous input data from the mySQL DB table where the dat is written, but when the data displays the input form goes away (all expect the submit button that is). I've come across this subject here, but could never quite find the answer that worked for me.
**`models.py`**
class UnitPool(models.Model):
# rack = models.ForeignKey(Rack)
# platform = models.ForeignKey(Group)
location = models.CharField(max_length=10, choices=LAB, default='Choose', blank=False)
rack = models.CharField(max_length=10, choices=RACKS, default='Choose', blank=False)
platform = models.CharField(max_length=10, choices = PLATFORM, default='Choose',blank=False)
unit_HW_Serial = models.CharField(max_length=20, blank=False, null=False)
unit_SW_Serial = models.CharField(max_length=20, blank=False, null=False)
unit_SKU = models.CharField(max_length=20, blank=False, null=False)
comments = models.CharField(max_length=64, blank=True, null=True, default='')
def __unicode__(self): # __unicode__ on Python 2
return '%s %s %s %s %s %s' % (self.rack,
self.platform,
self.unit_HW_Serial,
self.unit_SW_Serial,
self.unit_SKU,
self.comments)
class UUTForm(ModelForm):
class Meta:
model = UnitPool
widgets = {
'comments': TextInput(attrs={'size': 10}),
}
fields = ['location','rack', 'platform','unit_HW_Serial','unit_SW_Serial','unit_SKU','comments']
**forms.html**
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="container">
<div class='row'>
<div class='col-md-2'>
{% if title %}
<h1 class='{% if title_align_center %}text-align-center{% endif %}'>{{ title }}</h1>
{% endif %}
<form method='POST' action=''>{% csrf_token %}
{{ form|crispy }}
<input class='btn btn-primary' type='submit' value='Add Unit' />
</form>
</div>
</div>
</div>
{% if queryset %}
{% if rack != '' %}
<div class="container">
<div class="row">
<div class='col-md-8 col-md-offset-3'>
<h1>Unit Data Entered</h1>
<table class='table'>
<td><b>Item</b></td>
<td><b>Location</b></td>
<td><b>Rack#</b></td>
<td><b>Platform</b></td>
<td><b>HW SN</b></td>
<td><b>SW SN</b></td>
<td><b>SKU</b></td>
<td><b>Comment</b></td>
{% for instance in queryset %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ instance.location }}</td>
<td>{{ instance.rack }}</td>
<td>{{ instance.platform }}</td>
<td>{{ instance.unit_HW_Serial }}</td>
<td>{{ instance.unit_SW_Serial }}</td>
<td>{{ instance.unit_SKU }}</td>
<td>{{ instance.comments }}</td>
</tr>
{% endfor %}
</table>
</div>
</div>
</div>
{% endif %}
{% endif %}
{% endblock %}
**views.py**
from django.conf import settings
from django.shortcuts import render
from .models import UnitPool, UUTForm
def labunits(request):
title = 'Enter Info'
form = UUTForm(request.POST or None)
context = {
"title": title,
"form": form
}
if form.is_valid():
instance = form.save(commit=False)
instance.save()
queryset = UnitPool.objects.all().order_by('rack','platform')
context = {
"queryset": queryset
}
return render(request, "labunits/forms.html", context)
You need to pass the form in the context after calling .is_valid() as #Daniel also mentioned.
Since you are not passing the form in the context again after calling the .is_valid() function, the form does not get displayed again in the template.
So, when you are resetting the context, you need to pass the form also.
def labunits(request):
title = 'Enter Info'
form = UUTForm(request.POST or None)
context = {
"title": title,
"form": form
}
if form.is_valid():
instance = form.save(commit=False)
instance.save()
queryset = UnitPool.objects.all().order_by('rack','platform')
context = {
"queryset": queryset,
"form" : form # pass the form in the context
}
return render(request, "labunits/forms.html", context)