My goal is to create a page that lists all the courses available in the database and have the user select which courses they would like to be a tutor for.
I have a CustomUser model, a courses model, and finally a TutorTeachesCourse model that takes user and courses as foreign keys.
# model.py
from django.contrib.auth.models import AbstractUser
class CustomUser(AbstractUser):
is_tutee = models.BooleanField(default=False)
is_tutor = models.BooleanField(default=False)
courses = models.ManyToManyField(Courses)
class Courses(models.Model):
course_name = models.CharField(max_length=100, null = False)
course_number = models.CharField(max_length=100, null = False)
department = models.ForeignKey(Department, on_delete=models.CASCADE)
course_description = models.CharField(max_length=1000, blank=True)
#tutor = models.ManyToManyField(CustomUser) #moved m2m relationship to user model
objects = models.Manager()
def __str__(self):
return self.course_name
# forms.py
class EditTutoredCoursesForm(forms.Form):
model = CustomUser
course = forms.ModelMultipleChoiceField(
queryset = Courses.objects.all(),
widget = forms.CheckboxSelectMultiple,
)
def clean(self):
cleaned_data = super(EditTutoredCoursesForm, self).clean()
is_tutor = cleaned_data.get('is_tutor')
if not is_tutor:
raise forms.ValidationError('Validation error.')
def save(self,commit=True):
rel=super(EditTutoredCoursesForm,self).save(commit=False)
rel.is_tutor=self.cleaned_data['is_tutor']
if commit:
rel.save()
return rel
# views.py
def edit_tutored_courses(request):
user = request.user
if request.method == 'POST':
form = EditTutoredCoursesForm(request.POST)
if form.is_valid():
user.courses.set(form.cleaned_data['courses'])
user = form.save(commit=True)
messages.success(request, 'Success!')
return redirect(reverse('view_profile'))
else:
form = EditTutoredCoursesForm()
context = {
'form' : form,
}
return render(request, 'edit_tutored_courses.html', context)
And here the page where the user selects/unselects the courses they wish to tutor/not tutor.
# edit_tutored_courses.html
<table style="width:50%">
<tr>
<th>Course Name</th>
</tr>
<form method="POST" action="">
{% csrf_token %}
{% for is_tutor in form %}
{% for course in is_tutor %}
<tr>
<td>{{ course }}</td>
<td>{{ user }}</td>
</tr>
{% endfor %}
{% endfor %}
</table>
<input type="submit" value="Save Changes"/>
</form>
I can display the courses on my page but I don't know how to make changes to the database. I want the checkboxes to mean that once I click "submit" the table TutorTeachesCourses populates with that user with the checked courses, and if I uncheck the boxes it means it deletes the existing one. (That means I also need to make the page automatically check the boxes that exists int he database. How do I do all of this?
Related
I have been having a problem working with formsets in my project and I've been trying to get to the bottom of this. While doing so, a couple of different errors have been appearing. Generally, what I want to do is create an object of entity A (workout) and get redirected to a template/url that lets me "fill" it with objects of entity B, which I will be making at that point dynamically using model formsets. The problem seems to be revolving around the form, more specifically: if I write the fields one by one, as in :
CycleFormSet = modelformset_factory(
Cycle, fields=('reps', 'place_in_workout', 'exercise', 'number_of_times', 'break_inbetween'), extra=1
)
Then, I get the error: Unknown field(s) (place_in_workout, break_inbetween, reps, number_of_times) when I attempt to run the server. If I use exclude for some field, or do fields = 'all' , then I don't get an error at this point. However, I get the error : ['ManagementForm data is missing or has been tampered with'] when I try to post the data of the workout object. Me code:
models.py
class Exercise(models.Model):
name = models.CharField(max_length=150)
description = models.TextField(max_length=500)
def __str__(self):
return self.name
class Workout(models.Model):
name = models.CharField(max_length=150, null=True)
created_by_user = models.ForeignKey(User, null=True, on_delete=models.RESTRICT)
description = models.TextField(max_length=1000, null=True)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
class Cycle(models.Model):
place_in_workout = models.IntegerField
exercise = models.ManyToManyField(Exercise)
number_of_times = models.IntegerField
reps = models.IntegerField
break_inbetween = models.IntegerField
workout = models.ManyToManyField(Workout)
class WorkoutCompleted(models.Model):
datetime = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(User, on_delete=models.RESTRICT)
forms.py
class CreateUserForm(UserCreationForm):
class Meta:
model = User
fields = ['username', 'email', 'password1', 'password2']
class WorkoutForm(forms.ModelForm):
class Meta:
model = Workout
fields = ['name', 'description']
class ExerciseForm(forms.ModelForm):
class Meta:
model = Exercise
fields = ['name', 'description']
CycleFormSet = modelformset_factory(
Cycle, fields='__all__', extra=1
)
urls.py
urlpatterns = [
path('register/', views.register_page, name='register'),
path('login/', views.login_page, name='login'),
path('logout', views.logout_page, name='logout'),
path('', views.index, name='index'),
path('browse/', views.browse, name='browse'),
path('workouts/<str:user_id>/', views.workouts, name='workouts'),
path('add_exercise/', views.add_exercise, name='add_exercise'),
path('create_workout/<str:user_id>/', views.fill_workout, name='fill_workout')
]
views.py
#login_required(login_url='login')
def workouts(request, user_id):
context = {}
if request.method == 'POST':
form = WorkoutForm(request.POST)
if form.is_valid():
workout = form.save(commit=False)
workout.created_by_user = request.user
workout.save()
workout_id = workout.id
context = {'workout_id': workout_id}
return render(request, 'Trainmate/fill_workout.html', context)
else:
form = WorkoutForm()
workout_programs = Workout.objects.all()
user_workouts = workout_programs.filter(created_by_user=user_id)
context = {'user_workouts': user_workouts, 'form': form}
return render(request, 'Trainmate/workouts.html', context)
#login_required(login_url='login')
def fill_workout(request, user_id):
if request.method == 'POST':
# workouts = Workout.objects.filter(created_by_user__exact=request.user).order_by('-created_at')
# current_workout = workouts[0]
# pk_workout = current_workout.id
pk_workout = 1
formset = CycleFormSet(request.POST)
if formset.is_valid():
for form in formset:
cycle = form.save(commit=False)
cycle.workout = Workout.objects.get(pk=pk_workout)
cycle.save()
context = {}
return render(request, 'Trainmate/home.html', context)
else:
formset = CycleFormSet(queryset=Cycle.objects.none())
context = {'formset': formset}
return render(request, 'Trainmate/fill_workout_with_sets', context)
(there are more views, I didn't include some views about login/logout, if asked, I will, I didn't want to make the post even bigger than it's already going to be). Also, I have run the views with the commented section, I believe I am doing some mistake with queryset, therefore I gave the pk_workout=1 so that the fault in the query set is not relevant. There is at least a workout object in the database at all times.
workouts.html
{% extends 'Trainmate/main.html' %}
{% block content %}
<h1>My Workouts</h1>
<div>
{% for workout in user_workouts %}
<tr>
<td>{{ workout.name }}</td>
<td><a class="btn btn-sm btn-info" href="">Update</a></td>
<td><a class="btn btn-sm btn-info" href="">Delete</a></td><br>
</tr>
{% endfor %}
</div>
<h1>Create new Workout</h1>
<form method="POST" action="{% url 'fill_workout' request.user.id %}">
{% csrf_token %}
{{ form }}
<input type="submit" value="Create Workout">
</form>
{% endblock %}
fill_workout.html
{% extends 'Trainmate/main.html' %}
{% block content %}
<h1>Fill workout with sets</h1>
<form id="form_container" method="POST" action="">
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset %}
<div class="set_form">
{{ form.as_p }}
</div>
{% endfor %}
<button id="add-form" type="button">Add another set</button>
<button type="submit"> Create Cycle</button>
</form>
let set_form = document.querySelectorAll(".set_form")
let container = document.querySelector("#form_container")
let add_button = document.querySelector("#add_form")
let total_forms = document.querySelector("#id_form-TOTAL-FORMS")
let form_num = set_form.length -1
add_button.addEventListener('click',add_form)
function add_form(e){
e.preventDefault()
let new_form = set_form[0].cloneNode(true)
let form_regex = RegExp(`form-(\\d){1}-`,'g')
form_num ++
new_form.innerHTML = new_form.innerHTML.replace(form_regex, `form-${form_num}-`)
container.insertBefore(new_form, add_button)
total_forms.setAttribute('value', `${form_num + 1}`)
}
{% endblock %}
I tried to run the server and complete the form with the name and description of the workout object without the javascript part of the template above, I still get the same error.
Sorry for the long post and the , I have been trying to narrow down my problem as much as I can before posting, but it seems I get nowhere.
You need to initialise the fields when you define them in your models, you are missing the parenthesis () from your model fields in the Cycle model
class Cycle(models.Model):
place_in_workout = models.IntegerField()
exercise = models.ManyToManyField(Exercise)
number_of_times = models.IntegerField()
reps = models.IntegerField()
break_inbetween = models.IntegerField()
workout = models.ManyToManyField(Workout)
I want the logged in user to be able to add users to a team they have created. At the moment I have created a form which lets the user select the user and the team they want to add them to, but they can select from every team in the database rather than just those they have created. Any ideas? These are my models, view and the form i have created. Also help with what to put in my HTML file would be appreciated.
Models:
class UserTeams(models.Model):
userID = models.ForeignKey(User,on_delete=models.CASCADE)
teamID = models.ForeignKey(Team,on_delete=models.CASCADE)
class Team(models.Model):
name = models.CharField(max_length=100)
venue = models.CharField(max_length=100)
countryID = models.ForeignKey(Countries, on_delete=models.CASCADE)
owner = models.ForeignKey(User)
View:
def invite(request):
if request.method == 'POST':
form = InvitePlayerForm(request.POST)
if form.is_valid():
userteam = form.save(commit=False)
userteam.save()
else:
form = InvitePlayerForm()
query = UserTeams.objects.all()
return render(request, 'teammanager/invite.html', {
"invite": query,
"form": form
})
Form:
class InvitePlayerForm(forms.ModelForm):
class Meta:
model = UserTeams
fields = ['userID','teamID']
HTML:
{% extends "teammanager/header.html" %}
{% block content %}
<html>
<body>
<h4>Invite players to your team</h4>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
</form>
{% endblock %}
Modify your form like so it will do the FK filter based on the userteam object.
class InvitePlayerForm(forms.ModelForm):
class Meta:
model = UserTeams
fields = ['userID','teamID']
def __init__(self,user,*args,**kwargs):
super(InvitePlayerForm,self ).__init__(*args,**kwargs)
self.fields['teamID'].queryset = Team.objects.filter(id__in = UserTeam.objects.filter(userID = user))
Fields I have added in django forms are not visible on webpage.
Attached model, view and html for the reference below.
This is an additional filed which I intent to add to the forms, I am new to Django and learning by enhancing the current project.
"estimated_headcount" is the new filed I have added in the forms.
Thanks
Model
class EstimatedHeadcount(models.Model):
count = models.CharField(max_length=100)
def __unicode__(self):
return self.name
class Meta:
default_permissions = []
#staticmethod
def __gotoadmin__():
return True
forms.py
class ClientProfileForm(forms.ModelForm):
class Meta:
model = ClientProfile
fields = ('full_name', 'short_name', 'account_payable',
'require_job_number', 'currency', 'segment', 'market', 'estimated_headcount', 'is_technicolor',
'address')
views.py
def client_profile(request):
all_profiles = ClientProfile.objects.filter(status='active')
profile = None
pid = request.GET.get('pid')
client_profile_form = ClientProfileForm()
if pid:
profile = ClientProfile.objects.get(id=pid)
client_profile_form = ClientProfileForm(instance=profile)
if request.method == 'POST':
client_profile_form = ClientProfileForm(request.POST, instance=profile)
if client_profile_form.is_valid():
profile = client_profile_form.save()
profile.csv_mapping = profile.full_name
profile.save()
if profile:
for task_type in TaskType.objects.all():
if not profile.task_costs.filter(task_type=task_type):
task_cost = TaskCost(task_type=task_type)
task_cost.save()
profile.task_costs.add(task_cost)
return render(request, "prod/client_profile.html", {'all_profiles': all_profiles,
'profile': profile,
'client_profile_form': client_profile_form})
clientprofile.html
<div class="content">
<form id='add_new_client_form' method="post" action="">
{% csrf_token %}
<table class="table">
<tbody>
{{ client_profile_form.as_table }}
</tbody>
<tfoot>
<tr>
<td></td>
<td>
<button class="lock" type="button"
onclick="unlock(this, '#add_new_client_form')">Unlock
</button>
<button type="submit">SAVE</button>
</td>
</tr>
</tfoot>
</table>
</form>
</div>
As far as I can tell from your code, there is no relation between the ClientProfile model and the EstimatedHeadcount model.
estimated_headcount should be a field on the ClientProfile model.
class ClientProfile(models.Model):
...
estimated_headcount = models.CharField(max_length=100)
Side note: I would expect the estimated headcount to be a numeric value, so an IntegerField or PositiveIntegerField might be a better choice.
I’m having difficulty implementing initial data in my django formset.
For context, I’m building an attendance app where a list of students exist and need to be assessed for attendance every day.
What I’m trying to do is have an administrator click on a link which has a date listed on it. They will then be taken to data grid where each row represents the number of students in the system along with 4 columns (student name, date, present/absent drop down, a notes field). The goal is to have the student name field be pre-populated with the the list of students in the Student model, the date field be pre-populated with the date on the link the user clicked and the attendance and notes fields be user inputs.
Any help would be much appreciated
Thanks!
—
Student model
class Student(models.Model):
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
GENDER_CHOICES = (
('male', 'male'),
('female', 'female'),
)
gender = models.CharField(max_length=12, choices=GENDER_CHOICES, null=False, blank=False)
date_of_birth = models.DateField(auto_now=False, auto_now_add=False)
#property
def full_name(self):
return ''.join([self.first_name, '_', self.last_name])
def __unicode__(self):
return self.full_name
Attendance model
class Attendance(models.Model):
student = models.ForeignKey('students.Student')
attendance_date = models.DateField(auto_now=False, auto_now_add=False)
STATUS_CHOICES = (
('present', ‘1’),
('absent', ‘0’),
)
status = models.CharField(max_length=12, choices=STATUS_CHOICES, null=False, blank=False)
notes = models.CharField(max_length=300, null=True, blank=True)
class Meta:
unique_together = ("student", "attendance_date")
def __unicode__(self):
return self.student
Attendance form
class AttendanceForm(forms.ModelForm):
class Meta:
model = Attendance
fields = ["student","attendance_date", "status", "notes"]
View
def add_attendance(request):
s = Student.objects.all().values()
AttendanceFormSet = formset_factory(AttendanceForm, extra=0)
formset = AttendanceFormSet(request.POST or None, initial=s)
if formset.is_valid():
try:
instance = form.save(commit=False)
instance.save()
return HttpResponseRedirect('/')
except:
return HttpResponseRedirect('/')
context = {
"formset": formset,
}
return render(request, "group_attendance.html", context)
Template
<table id="formset" class="form">
{{ formset.management_form }}
{% for form in formset.forms %}
{% if forloop.first %}
<thead><tr>
{% for field in form.visible_fields %}
<th>{{ field.label|capfirst }}</th>
{% endfor %}
</tr></thead>
{% endif %}
<tr>
{% 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>
I'm not really sure, if I understood your question the intended way. I think you're looking for a way to generate dynamic forms, which were pre-filled with data from the db.
A really helpful article about that, can be found here https://jacobian.org/writing/dynamic-form-generation/
You don't have a fixed numbers of students (-> fields in form), so you have to generate as many fields as needed. So you have to iterate over the students and create a form field for every single one.
You can find this in the article above. Just down below is a code snippet and an explanation of it:
class UserCreationForm(forms.Form):
username = forms.CharField(max_length=30)
password1 = forms.CharField(widget=forms.PasswordInput)
password2 = forms.CharField(widget=forms.PasswordInput)
def __init__(self, *args, **kwargs):
extra = kwargs.pop('extra')
super(UserCreationForm, self).__init__(*args, **kwargs)
for i, question in enumerate(extra):
self.fields['custom_%s' % i] = forms.CharField(label=question)
I have a form field that calls a queryset and uses the 'select' widget.
Is there a way to remove an option value from the queryset if it already has been 'added' to the cart?
In the select form, there's three options: Option A, Option B, Option C.
The user selects Option A, and clicks 'Add'. Now once the user clicks 'Add', I want to remove Option A from the select.
Only Option B and Option C will be available to choose from.
Can this be done just using Django+Python? Or will I need to use additional JS/jQuery?
Thanks!
models.py
class Pickup(models.Model):
# id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
user = models.ForeignKey(settings.AUTH_USER_MODEL, blank=False, null=True)
total = models.DecimalField(max_digits=100, decimal_places=2, default=0.00)
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
updated = models.DateTimeField(auto_now_add=False, auto_now=True)
active = models.BooleanField(default=True)
status = models.CharField(max_length=120, choices=STATUS_CHOICES, default="Open")
def __str__(self):
return "Pickup Order ID: %s" %(str(self.id))
class PickupItem(models.Model):
pickup = models.ForeignKey('Pickup', null=True, blank=True)
dropoffitem = models.ForeignKey(DropoffItem)
notes = models.TextField(null=True, blank=True)
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
updated = models.DateTimeField(auto_now_add=False, auto_now=True)
forms.py
class AddPickupItemForm(forms.ModelForm):
dropoffitem = forms.ModelChoiceField(queryset=DropoffItem.objects.all(), widget=forms.Select(attrs={'class':'form-control'}))
class Meta:
model = PickupItem
fields = ['dropoffitem']
views.py
def add_item_to_pickup_order(request):
request.session.set_expiry(120000)
try:
user = request.user
the_id = request.session['pickup_id']
pickup = Pickup.objects.get(id=the_id)
except:
user = request.user
new_pickup_order = Pickup(user=user)
new_pickup_order.save()
request.session['pickup_id'] = new_pickup_order.id
the_id = new_pickup_order.id
pickup = Pickup.objects.get(id=the_id)
try:
dropoffitem = DropoffItem.objects.get(id=id)
except DropoffItem.DoesNotExist:
pass
except:
pass
form = AddPickupItemForm(request.POST or None)
if request.method == "POST":
dropoffitem_id = int(request.POST['dropoffitem'])
pickup_item = PickupItem.objects.create(pickup=pickup, dropoffitem_id=dropoffitem_id)
pickup_item.save()
return HttpResponseRedirect('%s'%(reverse('add_item_to_pickup_order')))
context = {
"pickup": pickup,
"form": form,
}
return render(request, 'pickups/create_pickup_order.html', context)
.html
{% extends "base.html" %}
{% block content %}
<div class="row">
<div class="container">
<div class="col-xs-12">
<h1>Create Cart</h1>
<form method="POST" action="{% url 'add_item_to_pickup_order' %}">
{% csrf_token %}
<table class="table">
<thead>
<th>Item</th>
<th></th>
</thead>
<tr>
<td>{{ form.dropoffitem }}</td>
<td><input type="submit" value="Add Item" class="btn btn-default btn-primary" /></td>
</tr>
</table>
</form>
To exclude/remove an item from the queryset, you can use exclude.
YourModel.objects.exclude(id=4)
To exclude multiple items:
YourModel.objects.exclude(id__in=[4, 6, 10])
More info about exclude on Django docs.