Django formset with no initial data - python

I am a Django rookie and I am developing a small app to register time (duration) and quantity of activities per user per day. Sort of like a work log. My problem is this: My “add entry” view displays and updates old records rather than adding new records to the db. I need a view to add new records, not replace old ones.
From searching around and from the #django IRC channel, I understand that the formset-way by default draws on old data rather than setting the client up for adding new data. I have, however, not found anything about how to avoid this behaviour and have the client provide a blank form for "appending new data" rather than "editing existing data".
My deadline is drawing really close and all help is greatly appreciated.
Here are the relevant code snippets:
From models.py
class Activity(models.Model):
name = models.CharField(max_length=200)
description = models.TextField()
class Workday(models.Model):
entrydate = models.DateField()
worker = models.ForeignKey(User, on_delete=models.CASCADE)
class Entry(models.Model):
duration = models.DurationField()
quantity = models.PositiveIntegerField()
activity = models.ForeignKey(Activity, on_delete=models.CASCADE)
workday = models.ForeignKey(Workday, on_delete=models.CASCADE)
From forms.py
class EntryForm(ModelForm):
activity = ModelChoiceField(queryset=Activity.objects.order_by('name'), initial=0)
class Meta:
model = Entry
fields = ['activity',
'duration',
'quantity',
]
class WorkdayForm(ModelForm):
class Meta:
model = Workday
fields = ['entrydate']
widgets = {'entrydate': SelectDateWidget}
From views.py
def addentry(request):
EntryFormSet = modelformset_factory(Entry, form=EntryForm, extra=0, fields=('activity', 'duration', 'quantity'))
if request.method == 'POST':
workdayform = WorkdayForm(request.POST, prefix='workday')
formset = EntryFormSet(request.POST)
if formset.is_valid() and workdayform.is_valid():
# Generate a workday object
workday = workdayform.save(commit=False)
workday.entrydate = workdayform.cleaned_data['entrydate']
workday.worker = request.user
workday.save()
# Generate entry objects for each form in the entry formset
for form in formset:
e = form.save(commit=False)
e.workday = workday
e.save()
form.save_m2m()
messages.add_message(request, messages.SUCCESS,
"Registrert aktivitet " +
e.workday.entrydate.strftime('%A %d. %B %Y') +
": " + e.activity.name + " (" + str(e.quantity) +") - " +
str(e.duration)
)
return redirect('index')
else:
workdayform = WorkdayForm(request.POST, prefix='workday')
formset = EntryFormSet(request.POST)
for dict in formset.errors:
messages.add_message(request, messages.ERROR, dict)
context = {
'workdayform': workdayform,
'formset': formset,
}
return render(request, 'register/addentry.html', context)
else:
workdayform = WorkdayForm(prefix='workday')
formset = EntryFormSet()
context = {
'workdayform': workdayform,
'formset': formset,
}
return render(request, 'register/addentry.html', context)
From addentry.html
{% block content %}
{% if user.is_authenticated %}
<h1>Ny dag</h1>
{% if formset and workdayform %}
<form id="newdayform" method="POST" class="post-form">
{% csrf_token %}
{{ workdayform.as_p }}
{{ formset.management_form }}
<table>
<thead>
<tr>
<td>Aktivitet</td>
<td>Varighet<br/>(HH:MM:SS)</td>
<td>Antall</td>
</tr>
</thead>
<tbody>
{% for form in formset %}
<tr>
<td>{{ form.activity }}</td>
<td>{{ form.duration }}</td>
<td>{{ form.quantity }}</td>
<td class="hidden">{{ form.id }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<button type="submit">Registrer tid</button>
</form>
<script src="{% static 'register/jquery.formset.js' %}"></script>
<script type="text/javascript">
$(function() {
$('#newdayform tbody tr').formset();
})
</script>
{% if entryform.errors or workdayform.errors %}
<h3>Feil i utfyllingen</h3>
{{ entryform.errors }}
{{ workdayform.errors }}
{% endif %}
{% else %}
<p>No form!</p>
{% endif %}
{% endif %}
{% endblock %}

Thanks to #e4c5 and this previous Q&A, the issue is solved by passing a queryset of no objects to the formset, like this:
def addentry(request):
(...)
qs = Entry.objects.none()
formset = EntryFormSet(queryset=qs)
(...)

Related

Django forms data retrieving and updating problem

I've four fields in my models.py file.
class Item(models.Model):
product_name = models.CharField(max_length=100)
quantity = models.IntegerField()
size_choice = (
('S', 'Short'),
('M','Medium'),
('L','Long')
)
size = models.CharField(max_length=30, choices=size_choice,blank=True, null=True)
date = models.DateField(blank=True, null=True)
And this is my forms.py file:
class ItemForm(ModelForm):
class Meta:
model = Item
widgets = {'date':DateInput()}
fields = ['product_name','quantity']
As I'm taking two fields only so it will display only two fields in my additem.html file:
<form action="" method="post">
{% csrf_token %}
{{ form }}
<button type="submit">Add</button>
</form>
In my itemlist.html file I can retrieve 'product_name' and 'quantity' from database as it is being saved from additem.html file. But in this itemlist.html file I've created two more inputs for 'size' and 'date'. So from here i want to update data into database(all four coulmns). Updating two fileds is fine but how will i update 'size' and 'field' from itemlist.html file.
{% for neww in all %}
<tr>
<td>{{ neww.product_name }}</td>
<td>{{ neww.quantity }}</td>
<td><input type="text" value="{{ neww.size }}"</td> /* This */
<td><input type="text" value="{{ neww.date }}"</td> /* and this i want to update from here */
<td>Edit</tr>{% endfor %}
My update_item.html file:
<form action="" method="POST">
{% csrf_token %}
{{ form }}
<input type="submit" value="Update">
</form>
My itemlist views:
def itemlist(request):
all_items = Item.objects.all()
return render(request, 'item/itemlist.html',{'all': all_items})
And my update_item views:
def update_item(request, id):
if request.method == 'POST':
pi = Item.objects.get(pk=id)
fm = ItemForm(request.POST, instance=pi)
if fm.is_valid():
fm.save()
return redirect('/itemlist')
else:
pi = Item.objects.get(pk=id)
fm = ItemForm(instance=pi)
return render(request, 'item/update_item.html', {'form':fm})
I searched on Internet. I didn't find any similar question. I've stuck here since a week. Any help would be really appreciated.
First thing to note is that if you are requesting a form data from html template, then it should be under the form tag. and action "PATH TO THE URL containing the views." as following:
{% for neww in all %}
<tr>
<td>{{ neww.product_name }}</td>
<td>{{ neww.quantity }}</td>
<form action="PATH TO THE URL" method="POST">
{% csrf_token %}
<td><input type="text" value="{{ neww.size }}" name="val1"></td> /* This */
<td><input type="text" value="{{ neww.date }}" name="val2"></td> /* and this i want to update from here */
<input type="submit" value="Update">
</form>
<td>Edit
and in your views.py file you can request the data to update your tables in the database as following:
size = request.POST['val1']
date = request.POST['val2']
now you can use these values to be updated in the tables.
There are more options to achieve this functionality in case you want the data prefilled in the form partly using the instances and id. Just check on YouTube or google how to prefill the django form partly. You can also hide the form fields in the html using the css styles.
Try this :
def update_item(request, id):
if request.method == 'POST':
pi = Item.objects.get(pk=id)
fm = ItemForm(request.POST, instance=pi)
fm.size = request.POST["size"]
fm.date = request.POST["date"]
if fm.is_valid():
fm.save()
return redirect('/itemlist')
else:
pi = Item.objects.get(pk=id)
fm = ItemForm(instance=pi)
return render(request, 'item/update_item.html', {'form':fm})

When trying to create a new Django CreateView form, my forms are being populated with the data that was entered in the last form

Using Class Based Views, ModelForms, and Inlline Formsets. I’m making a recipe application in Django. Each user has their own OneToOne RecipeBook object, which in turn can hold as many recipes as needed, as each Recipe has a ForeignKey relationship to the RecipeBook object. There are also Ingredient and Direction objects that each have a FK relationship to the Recipe object.
The good news is that I can create a Recipe object using my CreateView, with as many associated Ingredient and Direction objects as I want. The Ingredient/Direction objects should be unique to each Recipe object (and by extension, each User). However, when I create a Recipe object, and then I try to create a new Recipe object, its Ingredient and Direction fields are already populated on the new object, form the old object. So if I had just created a Recipe with 3 Ingredient/Direction fields all set to '1', and then go to create another Recipe, the new Recipe object will have all blank fields, but will have 3 Ingredient/Direction objects all set to 1. This will happen to each user that is logged in. I want to make it so these objects are all staying together.
I think the issue to this is that either my get_context_data or my form_valid methods are saving the Ingredient/Direction objects globally, when I just want each Ingredient/Direction object to only be associated with the specific recipe object. I’ve tried messing with the init function of my Forms, I’ve tried querying for the object before/while its being created, and it seems like no matter what I do I’m just running in circles. I’d appreciate any help/resources anyone can point me towards!
My Models:
class RecipeBook(models.Model):
"""Each user has a single associated RecipeBook object, linked in this OneToOne field"""
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
class Recipe(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4())
recipebook = models.ForeignKey(RecipeBook, related_name='recipe_set', on_delete=models.CASCADE)
title = models.CharField(max_length=150, help_text='Title of the recipe')
description = models.TextField(help_text='Description of the recipe', blank=True)
# image = models.ImageField(height_field=, width_field=, help_text='Image of the recipe', blank=True)
servings = models.PositiveSmallIntegerField(help_text='The amount of servings the recipe will yield', default=0, blank=True)
prep_time = models.PositiveSmallIntegerField(help_text='The preparation time', default=0, blank=True)
cook_time = models.PositiveSmallIntegerField(help_text='The cooking time', default=0, blank=True)
url = models.URLField(blank=True)
TIME_UNITS = (
('m', 'Minutes'),
('h', 'Hours')
)
def get_absolute_url(self):
return reverse('recipe_book:recipe-detail', args=[str(self.id)])
def __str__(self):
return self.title
class Ingredient(models.Model):
recipe = models.ForeignKey(Recipe, related_name='ingredient_set', on_delete=models.CASCADE)
name = models.CharField(max_length=100)
amount = models.CharField(max_length=20, blank=True)
def __str__(self):
return self.name
class Direction(models.Model):
recipe = models.ForeignKey(Recipe, related_name='direction_set', on_delete=models.CASCADE)
step_instructions = models.TextField(help_text='Write the instructions of the step here')
My Forms:
class AddRecipeForm(ModelForm):
recipe = forms.ModelChoiceField(queryset=Recipe.objects.all())
class Meta:
model = Recipe
fields = ['title', 'description', 'servings', 'prep_time', 'cook_time', 'url']
class AddIngredientForm(ModelForm):
class Meta:
model = Ingredient
fields = ['name', 'amount']
# def __init__(self, *args, **kwargs):
# self.recipe = kwargs.pop('recipe')
# super(AddIngredientForm, self).__init__(*args, **kwargs)
#
# if not self.instance:
# self.fields['name'].initial = self.recipe.default_name
# self.fields['amount'].widget = forms.TextInput(required=False)
#
# def save(self, *args, **kwargs):
# self.instance.recipe = self.recipe
# ingredient = super(AddIngredientForm, self).save(*args, **kwargs)
# return ingredient
IngredientFormset = inlineformset_factory(Recipe, Ingredient, form=AddIngredientForm, extra=1, can_delete=True)
class AddDirectionForm(ModelForm):
class Meta:
model = Direction
fields = ['step_instructions']
# def __init__(self, *args, **kwargs):
# self.recipe = kwargs.pop('recipe')
# super(AddDirectionForm, self).__init__(*args, **kwargs)
#
# if not self.instance:
# self.fields['step_instructions'].initial = self.recipe.default_step_instructions
#
# def save(self, *args, **kwargs):
# self.instance.recipe = self.recipe
# direction = super(AddDirectionForm, self).save(*args, **kwargs)
# return direction
DirectionFormset = inlineformset_factory(Recipe, Direction, form=AddDirectionForm, extra=1, can_delete=True)
My View:
class RecipeListView(LoginRequiredMixin, generic.ListView):
model = models.Recipe
context_object_name = 'recipes'
# Using this method ensures that the only recipes that are displayed are the ones associated with each user
def get_queryset(self):
return models.Recipe.objects.filter(recipebook=self.request.user.recipebook)
class RecipeDetailView(LoginRequiredMixin, generic.DetailView):
model = models.Recipe
fields = ['title', 'description', 'servings', 'prep_time', 'cook_time', 'url']
context_object_name = 'recipe'
def get_queryset(self):
return models.Recipe.objects.filter(recipebook=self.request.user.recipebook)
# Classes used to actually create full recipe objects
class RecipeCreate(LoginRequiredMixin, CreateView):
model = models.Recipe
fields = ['title', 'description', 'servings', 'prep_time', 'cook_time', 'url']
def get_queryset(self):
return models.Recipe.objects.filter(recipebook=self.request.user.recipebook)
def get_context_data(self, **kwargs):
data = super(RecipeCreate, self).get_context_data(**kwargs)
#user = self.request.user
if self.request.POST:
data['ingredients'] = IngredientFormset(self.request.POST)
#queryset=models.Recipe.objects.filter(recipebook=self.request.user.recipebook))
data['directions'] = DirectionFormset(self.request.POST)
#queryset=models.Recipe.objects.filter(recipebook=self.request.user.recipebook))
else:
data['ingredients'] = IngredientFormset()
#queryset=models.Recipe.objects.filter(self.kwargs['id']))
data['directions'] = DirectionFormset()
#queryset=models.Recipe.objects.filter(self.kwargs['id']))
return data
def form_valid(self, form):
form.instance.recipebook = self.request.user.recipebook
context = self.get_context_data()
ingredients = context['ingredients']
directions = context['directions']
# self.object is the object being created
self.object = form.save()
if ingredients.is_valid():
ingredients.instance = self.object
ingredients.save()
if directions.is_valid():
directions.instance = self.object
directions.save()
return super(RecipeCreate, self).form_valid(form)
class RecipeUpdate(LoginRequiredMixin, UpdateView):
model = models.Recipe
fields = ['title', 'description', 'servings', 'prep_time', 'cook_time', 'url']
def get_context_data(self, **kwargs):
data = super(RecipeUpdate, self).get_context_data(**kwargs)
if self.request.POST:
data['ingredients'] = IngredientFormset(self.request.POST, instance=self.object)
#queryset=models.Recipe.objects.filter(recipebook=self.request.user.recipebook))
data['directions'] = DirectionFormset(self.request.POST, instance=self.object)
#queryset=models.Recipe.objects.filter(recipebook=self.request.user.recipebook))
else:
data['ingredients'] = IngredientFormset(instance=self.object)
#queryset=models.Recipe.objects.filter(recipebook=self.request.user.recipebook))
data['directions'] = DirectionFormset(instance=self.object)
#queryset=models.Recipe.objects.filter(recipebook=self.request.user.recipebook))
return data
def form_valid(self, form):
form.instance.recipebook = self.request.user.recipebook
context = self.get_context_data()
ingredients = context['ingredients']
directions = context['directions']
self.object = form.save()
if ingredients.is_valid():
ingredients.instance = self.object
ingredients.save()
if directions.is_valid():
directions.instance = self.object
directions.save()
return super(RecipeUpdate, self).form_valid(form)
My Template:
{% extends 'base-recipe.html' %}
{# https://simpleit.rocks/python/django/dynamic-add-form-with-add-button-in-django-modelformset-template/ #}
{% block content %}
<div class="container">
<div class="card">
<div class="card-header">Create Recipe</div>
<div class="card-body">
<form action="" method="POST"> {% csrf_token %}
{# table for the Recipe object, manually rendering it for more control #}
<table class="table">
<tr>
<td>{{ form.title.label_tag }}</td>
<td>{{ form.title }}</td>
</tr>
<tr>
<td>{{ form.description.label_tag }}</td>
<td>{{ form.description }}</td>
</tr>
<tr>
<td>{{ form.servings.label_tag }}</td>
<td>{{ form.servings }}</td>
</tr>
<tr>
<td>{{ form.prep_time.label_tag }}</td>
<td>{{ form.prep_time }}</td>
</tr>
<tr>
<td>{{ form.cook_time.label_tag }}</td>
<td>{{ form.cook_time }}</td>
</tr>
<tr>
<td>{{ form.url.label_tag }}</td>
<td>{{ form.url }}</td>
</tr>
</table>
{# table for the ingredient(s) object(s) #}
<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="{% cycle row1 row2 %} formset_row-{{ ingredients.prefix }}">
{% 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>
<table class="table">
{{ directions.management_form }}
{% for form in directions.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_row-{{ directions.prefix }}">-->
<tr class="formset_row-{{ directions.prefix }}">
{% for field in form.visible_fields %}
<td>
{# include the hidden fields #}
{% if forloop.first %}
{% for field in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% endif %}
{{ field.errors.as_ul }}
{{ field }}
</td>
{% endfor %}
</tr>
{% endfor %}
</table>
<input class="btn btn-primary" type="submit" value="Submit">
<a class="btn btn-danger" href="{% url 'recipe_book:index' %}">Back to the recipe list</a>
</form>
</div>
</div>
</div>
{% load static %}
<script src="{% static 'js/jquery.formsets.js' %}"></script>
<script type="text/javascript">
$('.formset_row-{{ ingredients.prefix }}').formset({
addText: 'Add Another Ingredient',
deleteText: 'Remove',
prefix: '{{ ingredients.prefix }}',
});
$('.formset_row-{{ directions.prefix }}').formset({
addText: 'Add another',
deleteText: 'Remove',
prefix: '{{ directions.prefix }}',
});
</script>
{% endblock %}
For anyone who also has this issue, here's the fix, from the Django forum's user KenWhitesell:
You can chase this down through the source code if you really want to
understand what’s going on, but the Reader’s Digest version is that an
inline formset is created under the assumption that the formset is
linked to an existing instance. If one isn’t supplied, it selects one
from the database.
The fix, for me, was in the CreateView's get_context_data() method: since we don't want the inline_formset to be querying for any objects on a CreateView, you have to explicitly tell it not to with a queryset parameter on the GET request like this:
def get_context_data(self, **kwargs):
data = super(RecipeCreate, self).get_context_data(**kwargs)
if self.request.POST:
data['ingredients'] = IngredientFormset(self.request.POST)
data['directions'] = DirectionFormset(self.request.POST)
else:
data['ingredients'] = IngredientFormset(queryset=models.Ingredient.objects.none())
data['directions'] = DirectionFormset(queryset=models.Direction.objects.none())
return data
Here's a link to our forum post discussing the issue: https://forum.djangoproject.com/t/my-forms-are-being-populated-with-the-data-that-was-entered-in-the-last-createview/6278/12

How do I set initial values on a Django form using CreateView

I have a form and wish to set some default values in the fields. My original solution using the View class works
# forms.py
ResultForm(forms.ModelForm):
class Meta:
model = Result
fields = ("date", "club", "goals_for", "goals_against")
...
#staticmethod
def get_initial():
initial = {
'date': datetime.today().date(),
'goals_for': 0,
'goals_against': 0,
}
return initial
and
# views.py
class EnterResultView(View):
template = 'results/enter_result.html'
def get(self, request):
form_class = ResultForm()
form_class.initial = form_class.get_initial()
context = {
'form_class': form_class
}
return render(request, self.template, context)
But if I convert to a CreateView I cannot get the fields to initialise
# views.py
class EnterResultView(CreateView):
template_name = 'results/enter_result.html'
form_class = ResultForm
form_class.initial = form_class.get_initial()
What must I do?
[EDIT added template]
<!-- results/enter_result.html -->
...
{% for field in view.form_class %}
<tr>
<td style="text-align: right">{{ field.label_tag }}</td>
<td>{{ field }}</td>
{% if field.errors %}
{% for error in field.errors %}
<td class="form-error">{{ error }}</td>
{% endfor %}
{% endif %}
</tr>
{% endfor %}
Views with a FormMixin [Django-doc] have a .get_initial() method [Django-doc], you thus can override this:
class EnterResultView(CreateView):
template_name = 'results/enter_result.html'
form_class = ResultForm
def get_initial(self):
return self.form_class.get_initial()
A CreateView constructs a form and passes this to the view as form, you should not use view.form_class, since that will construct another (new) form, without any parameters:
{% for field in form %}
…
{% endfor %}

django modelformset_factory raises form not valid: id Select a valid choice. That choice is not one of the available choices

i am trying to create a student attendance sheet in django using django modelformset_factory...but when i save the formset it thows me the id is not valid here is my implementation
i have two models one StudentAttendance and StudentClass:
1: the StudentAttendance model is responsible for stroring students
attendance data here is the example
class StudentAttendance(models.Model):
classroom_id = models.ForeignKey(ClassRoom, on_delete=models.CASCADE, related_name='student_attendance')
attendance_date = models.DateField()
student_id = models.ForeignKey(Student, on_delete=models.CASCADE, related_name='student_attendance')
status = models.CharField(max_length=20, choices=ATTENDANCE_CHOICES)
comment = models.CharField(max_length=150, blank=True)
#signed_by = models.ForeignKey(Teacher, on_delete=models.CASCADE)
date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.student_id)
2: the StudentClass model is a submodel that maps a student to his respective class
class StudentClass(models.Model):
"""
This is a bridge table to link a student to a class
when you add a student to a class we update the selected class capacity
"""
main_class = models.ForeignKey(ClassRoom, on_delete=models.CASCADE, related_name='class_student')
academic_year = models.ForeignKey(AcademicYear, on_delete=models.CASCADE)
student_id = models.ForeignKey(Student, on_delete=models.CASCADE, related_name='student_class')
#property
def is_current_class(self):
if self.academic_year.is_current_session:
return True
return False
def __str__(self):
return str(self.student_id)
So my forms.py implementation is:
class StudentsAttendanceForm(forms.ModelForm):
class Meta:
model = StudentAttendance
fields = ('status', 'comment')
#exclude = [
#'siqned_by',
#]
On my views.py:
def student_attendance_manager(request):
"""
this function is responsible for querying the attendance parameters and present the student multiple attendance form
"""
if request.method == "POST":
# get the class name , the attendance date and present the attendance form
class_name = get_object_or_404(ClassRoom, pk=request.POST['class_name']) # class name
attendance_date = request.POST['date_field'] # date
# get the students in the class which is current active
student = StudentClass.objects.filter(main_class=request.POST['class_name'])
# modelform creation
AttendanceFormSet = modelformset_factory(StudentAttendance, form=StudentsAttendanceForm, extra=0)
# initiate the form and pass in the required parameters ie: classroom_id, attendance_date
list_formset = AttendanceFormSet(queryset=student)
# initialise the class_name and attendance date
#for form_inst in list_formset:
#form_inst.fields['classroom_id'].initial = class_name
#form_inst.fields['attendance_date'].initial = attendance_date
template = 'attendance/students_attendance_form.html'
context = {
'class_name':class_name,
'attendance_form': list_formset,
}
return JsonResponse({'html_form': render_to_string(template, context, request=request)})
template = 'attendance/students_attendance_manager.html'
class_date_selector_form = ClassroomDateQueryForm(request.GET or None)
context = {
'choice_form':class_date_selector_form
}
return render(request, template, context)
when the User Posts the form to be submited this is how i handle the form:
def student_attendance_register(request):
if request.method == "POST":
students = StudentClass.objects.filter(main_class=request.GET['class_id'])
StudentsAttendanceFormSet = modelformset_factory(StudentAttendance, form=StudentsAttendanceForm, extra=0)
list_formset = StudentsAttendanceFormSet(request.POST, queryset=students)
if list_formset.is_valid():
list_formset.save()
return HttpResponse('valid')
else:
return HttpResponse(list_formset.errors)
on my template i display the form in a table and this is my implementation:
form.html:
<form class="js-mark-attendance" method="post" action="{% url 'attendance:student_attendance_register' %}?class_id={{ class_name.id }}">
{% csrf_token %}
<table class="table-striped table table-bordered" id="Student_attendance_table">
<thead>
<tr>
<th>#</th>
<th>Admission Number</th>
<th>Name</th>
<th>Status</th>
<th>Comment</th>
</tr>
</thead>
<tbody>
{{ attendance_form.management_form }}
{% for form_inst in attendance_form %}
{% for hidden in form_inst.hidden_fields %}
{{ hidden }}
{% endfor %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ form_inst.instance.student_id.admission_number }}</td>
<td>{{ form_inst.instance.student_id }}</td>
<td>{{ form_inst.status }}</td>
<td> {{ form_inst.comment }}</td>
{{ form_inst.classroom_id.as_hidden }}
{{ form_inst.attendance_date.as_hidden }}
{{ form_inst.student_id.as_hidden }}
</tr>
{% endfor %}
</tbody>
</table>
<div class="row">
<div class="col-md-12 d-flex justify-content-center">
<input type="submit" value="Mark Attendance" class="btn btn-success">
</div>
</div>
</form>
and this is the error that django throws after the user has clicked submit button:
id
Select a valid choice. That choice is not one of the available choices.
so my question is ... how can i handle this post request form and or if their is an alternative way of doing my task:
any leads will be much upreciated
oops....I found my problem was the wrong usage of modelsfomset_factory...

Django - How to check if id contains in a table column?

guys.
I want to check in my django template, if request.user exists in some row of column user in my table LeagueMember. The way I found is not working.
views.py
#login_required(login_url='login/')
def search_leagues(request):
if request.method == 'POST':
return redirect('join_league')
leagues = League.objects.all()
return render(request, 'search_leagues.html', { 'allleagues': leagues })
model.py
class League(models.Model):
league_owner = models.ForeignKey('auth.User')
league_name = models.CharField(max_length=30)
creation_date = models.DateTimeField()
def is_member(self):
member = LeagueMember.objects.get(league=self)
if member:
return True
else:
return False
class LeagueMember(models.Model):
league = models.ForeignKey('League', related_name='leaguemember_league')
user = models.ForeignKey('auth.User')
search_leagues.html
{% for league in allleagues %}
<tr>
<td class="center">{{ league.league_name }}</td>
<td class="center">{{ league.leaguemember_league.count}}/{{ league.leaguesettings_league.league_number_teams }}</td>
<td class="center">{{ league.leaguesettings_league.league_eligibility }}</td>
<td class="center">{{ league.leaguesettings_league.league_lifetime }}</td>
{% if request.user in league.leaguemember_league.user %}
DO SOMETHING!!!
{% else %}
{% if league.leaguemember_league.count < league.leaguesettings_league.league_number_teams %}
{% if league.leaguesettings_league.league_eligibility == "Private" %}
<form method="post" action="{% url 'joinleague' pk=league.id %}">
<td class="center">Soliticar</td>
</form>
{% elif league.leaguesettings_league.league_eligibility == "Public" %}
<form method="post" action="{% url 'joinleague' pk=league.id %}">
<td class="center">Entrar</td>
</form>
{% endif %}
{% endif %}
{% endif %}
</tr>
{% endfor %}
This error is in this line:
{% if request.user in league.leaguemember_league.user %}
Always goes to ELSE block
Thank you all
league.leaguemember_league will not give you a LeagueMember object but a RelatedManager object (so you cannot find a user property in it, therefore your template logic will not work).
What you are trying to do is go two levels deep in your relationship (League -> LeagueMember -> User). You can't easily do this kind of logic in your template and probably need to do it in your view code instead. For example:
league_data = []
for league in League.objects.all():
league_data.append({
'league': league,
'users': User.objects.filter(leaguemember__league=league) # This gives you all the users that are related to this league
})
return render(request, 'search_leagues.html', { 'allleagues': league_data})
You then need to modify all your template logic to use this new structure:
{% for league_data in allleagues %}
# Replace league with league_data.league in all the template logic below this
In the if block you can then do:
{% if request.user in league_data.users %}
Note that this querying may not be very efficient if you have a large number of users/leagues - in which case you may need to rethink your model design.

Categories

Resources