I'm creating a website for general education uses and one of the features is a calendar section where I would like the user to be able to store their events but then when they login they can view the events they created. This is for an academic assignment.
I can't seem to get this calendar to link to a user field. I would like each record in the calendar table to have a user_id which will be the same as the current_user. I understand that you can user the django default user auth but i have not done that due to not knowing about it and by the time I realized it was too late.
So all I really need to do is when the form is valid, I need to assign the value of the current_user id as the value for student in the calendar table. But for some reason I keep getting problems and the form isn't detected as being valid or the program just doesn't assign the value.
My main objective is to have each user view their own calendar. I don't mind changing the current student field to a foreign key field
Student.Views
def calendar(request):
student_obj = Student.objects.get(student_name=current_user)
print(student_obj)
if request.method == 'POST':
form = EventsForm(initial={'student': '3'} or request.POST)
print(form.errors)
if form.is_valid():
form.save()
all_events = Events.objects.filter(student=student_obj.id)
messages.success(request, 'Event Has Been Added')
return render(request, 'Student/calendar.html', {'all_events': all_events})
else:
messages.success(request, 'Event Has NOT Been Added')
all_events = Events.objects.filter(student=student_obj.id)
return render(request, 'Student/calendar.html', {'all_events': all_events})
Student.Models
class Student(models.Model):
student_name = models.CharField(max_length=59, default=None)
username = models.CharField(max_length=59)
password = models.CharField(max_length=59)
age = models.PositiveIntegerField()
date_of_birth = models.DateField(max_length=10)
form = models.CharField(max_length=3)
email = models.EmailField(max_length=59)
present = models.PositiveIntegerField(default=0)
late = models.PositiveIntegerField(default=0)
absent = models.PositiveIntegerField(default=0)
maths_grade = models.PositiveIntegerField(default=0)
english_grade = models.PositiveIntegerField(default=0)
science_grade = models.PositiveIntegerField(default=0)
behaviour_level = models.PositiveIntegerField(default=0)
def __str__(self):
return self.student_name
class Events(models.Model):
student = models.CharField(max_length=200)
date = models.DateField(max_length=10, default=None)
event = models.CharField(max_length=200)
completed = models.BooleanField(default=False)
Student.forms
class EventsForm(forms.ModelForm):
class Meta:
model = Events
fields = ["event", "completed", "date", "student"]
Calendar Template
<div class="container" style="color: #fff">
<br/>
{% if messages %}
{% for message in messages %}
<div class="alert alert-warning alert-dismissible" roles="alert">
<button class="close" data-dismiss="alert">
<small>x</small>
</button>
{{ message }}
</div>
{% endfor %}
{% endif %}
{% if all_events %}
<div>
<table class="table table-dark table-bordered">
{% for things in all_events %}
{% if things.completed %}
<style>
.striker {
text-decoration: line-through;
text-color: black;
}
</style>
<tr class="table-danger striker">
<td style="color: black">{{ things.date }}</td>
<td>{{ things.event }}</td>
<td><center>Delete</center></td>
</tr>
{% else %}
<tr>
<td>{{ things.date }}</td>
<td >{{ things.event }}</td>
<td><center>Delete</center></td>
</tr>
{% endif %}
{% endfor %}
</table>
</div>
{% endif %}
Change form.save() to
event = form.save(commit=False)
event.student = request.user
event.save()
That'll do it.
Don't make it complicated, this have to be easier. If I understood what are you trying to do I would create my models as following:
#model.py
from django.db.models.signals import post_save
from django.dispatch import receiver
class Student(models.Model):
user= models.OneToOneField(User, null=True) #student is user
#Define student fields...
class Calendar(models.Model):
#Defile calender fields here along with its default values ...
user = models.OneToOneField(Student)
'''
this signal populate calender table with user_id along with its
calender fields
'''
#receiver(post_save, sender=Student)
def create_student_calender(sender, instance, created, **kwargs):
if created and not kwargs.get('raw', False):
calendar = Calender(user=instance)
calendar.save()
class Event(models.Model):
calender = models.ForeignKey(Callender, null=True)
# Define event fields here ...
With models structure like this, whenever student create account Calendar model will be populated saved with calendar fields and student's id field.
So how do student create their events? Simply create an a inlineformset_factory form to create events on each student's calendar like this:
#form.py
from django.forms import inlineformset_factory
from django import forms
class EventForm(forms.ModelForm):
#Events form fields here...
class Meta:
model = Event
fields = ["Event's field"]
EventFormSet = inlineformset_factory(Calender, Event, form=EventForm,
max_num=1, can_delete=False)
Render this formset with a view for student to create their events,the formset automatically associate student's event to calendar.
So you can add your logic to do more.
Related
I have previously figured out how to send and save notifications by many to many fields to send to users, now i can't specifically call the notifications by current user logged in i.d.
Models.py
class Notifications(models.Model):
id=models.AutoField(primary_key=True)
sent_to = models.ManyToManyField(CustomUser)
message = models.TextField(null=True)
message_reply = models.TextField(null=True)
created_at=models.DateTimeField(auto_now_add=True)
updated_at=models.DateTimeField(auto_now=True)
The notifications_sent_to is the created table after I created the many to many save
Notifications_sent_to table (which is not created in the models)
Notifications table (which stores the message)
Views.py
def add_notification(request):
notifs = Notifications.objects.all()
users = CustomUser.objects.filter(is_staff=True)
if request.method == 'POST':
form = AddNotifForm(request.POST)
if form.is_valid():
instance = form.save(commit=False)
instance.message_reply = "none"
instance.save()
form.save_m2m()
sent_to = form.cleaned_data.get('sent_to')
messages.success(request, f'Message has been successfully sent .')
return redirect('add_notif')
else:
form = AddNotifForm()
context={
'notifs' : notifs,
'form' : form,
'users' : users,
}
template_name ='main-admin/add-notif.html'
return render(request, template_name, context)
Forms.py
class AddNotifForm(forms.ModelForm):
sent_to = forms.ModelMultipleChoiceField(
queryset=CustomUser.objects.filter(is_staff=True).exclude(is_superuser=True),
widget=forms.CheckboxSelectMultiple,
required=True)
class Meta:
model = Notifications
fields = ['sent_to', 'message']
Templates view
{% for sent_to_users in sent_to_users %}
<tr>
<td>{{ sent_to_users.id }}</td>
<td>{{ sent_to_users.sent_to }}</td>
<td>{{ sent_to_users.message }}</td>
<td>
{% if sent_to_users.message_reply == "none" %}
<button type="button" class="btn btn-primary reply_open_modal" data-bs-toggle="modal" data-bs-target="#replyModal">Reply</button>
{% else %}
{{ sent_to_users.message_reply }}
{% endif %}
</td>
<td>{{ sent_to_users.created_at }}</td>
</tr>
{% endfor %}
I need help with solving an issue regarding duplicate database query's for each form in an inlineformset. I have a page where users can add and edit books belonging to an author.
models.py
from django.db import models
class Author(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=100)
class Book(models.Model):
id = models.AutoField(primary_key=True)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
title = models.CharField(max_length=100)
category_idcategory = models.ForeignKey(Category, models.DO_NOTHING)
class Category(models.Model):
name = models.CharField(max_length=100)
forms.py
from django import forms
class BookForm(forms.ModelForm):
class Meta:
model = Book
fields = '__all__'
views.py
instance = get_object_or_404(Author, id=id)
form = inlineformset_factory(Author, Book, form=BookForm, can_delete=True, extra=5)
formset = form(request.POST or None, instance=instance)
if request.method == "POST":
if formset.is_valid():
instanceForm = formset.save(commit=False)
for obj in instanceForm:
obj.save()
for obj in formset.deleted_objects:
obj.delete()
return HttpResponseRedirect(URL)
When I run the template, it performs a database query to the Category model for each form in formset. How do I prevent those duplicates? I dont know where to put select_related or prefetch_related. If instances of Book model grows to a large number, the page load times are getting very slow.
template.html
<table class="table table-sm">
{{ formset.management_form }}
<thead>
<td>Title</td>
<td>Category</td>
<td>delete</td>
</thead>
<tbody>
{% for obj in formset %}
{{ obj.id }}
<tr>
<td>{{ obj.title }}</td>
<td>{{ obj.category_idcategory }}</td>
<td>{{ obj.DELETE }}</td>
</tr>
{% endfor %}
</tbody>
</table>
You can change the queryset of a formset like this:
class InlineBookFormSet(BaseInlineFormSet):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Here is where to put the select_related.
self.queryset = Book.objects.select_related('category_idcategory').all()
then in your factory method call:
# Use your custom InlineBookFormSet
form = inlineformset_factory(Author, Book, form=BookForm, can_delete=True, extra=5, formset=InlineBookFormSet)
I am working on an attendance management system. I want to modify attendance of students.
class Subject(models.Model):
subject_name = models.CharField(max_length=20)
#attendance = models.ForeignKey(Attendance, on_delete = models.DO_NOTHING)
attendance = models.IntegerField(default=0)
def __str__(self):
return self.subject_name
class Section(models.Model):
section_name = models.CharField(max_length=20)
subject = models.ManyToManyField(Subject)
def __str__(self):
return self.section_name
class Student(models.Model):
rollno = models.IntegerField()
name = models.CharField(max_length=20)
section = models.ForeignKey(Section, on_delete = models.DO_NOTHING, default=0)
def __str__(self):
return str(self.rollno) + self.name
Here is my template. (Student.html)
{% for i in data %}
<tr>
<td>{{ i.rollno }}</td>
<td>{{ i.name }}</td>
<td> <button class='btn btn-danger' id='{{i.rollno}}' on click = "{{ i.section.subject.get(subject_name='java').attendance)|add:1 }}">
</td>
</tr>
{% endfor %}
I am getting error in using .get() method in template. I want to add (+1) attendance on a button click.
I strongly suggest to go through Django Tutorial. You will learn Django MVC concepts and able to achieve what you asked easily. The below code will help you get started.
views.py
def increment_attendance(request, subject_id):
"""Increment Attendance for a Subject"""
subject = Subject.objects.get(id=subject_id)
# check if record exists
if not subject:
raise Http404("Invalid subject_id")
# can also use only get_object_or_404(Subject, pk=subject_id)
# increment attendance
subject.attendance += 1
# save / commit to database
subject.save()
# redirec to 'some' page or previous page?
return redirect('top')
add this path to your urls.py
path('subject/<int:day>/increment_attendance', views.increment_attendance, name='increment_attendance')
template
<a class="btn btn-danger" id="{{i.rollno}}" href="{% url 'increment_attendance' subject_id=subject_id" %}"></a>
I am facing issues in saving data to my sqlite db using Django.
When i am accessing 127.0.0.1/personal/makeentry--> the page shows the form , but when i click on submit after entering the details, the detils are not saved in db.
Below is the code
model.py
from django.db import models
class Account(models.Model):
accountId = models.IntegerField(primary_key=True,unique=True,
blank=False, null=False, auto_created=True)
accountName = models.CharField(max_length=100)
countryName = models.CharField(max_length=100)
marketName = models.CharField(max_length=100)
msdmName = models.CharField(max_length=100)
deliveryManagedFrom = models.CharField(max_length=100)
location = models.CharField(max_length=100)
def __str__(self):
return self.accountName
admin.py
from django.contrib import admin
from .models import Account
# Register your models here.
class AccountAdmin(admin.ModelAdmin):
list_display = ['accountId', 'accountName','countryName', 'marketName',
'msdmName','deliveryManagedFrom','location']
admin.site.register(Account, AccountAdmin)
forms.py
from django import forms
from . models import Account
from django.forms import ModelForm
class AccountForm(forms.Form):
accountName = forms.CharField(label="Account Name", max_length=100)
countryName = forms.CharField(label="Country Name", max_length=100)
marketName = forms.CharField(label="Market Name", max_length=100)
msdmName = forms.CharField(label="MSDM Name", max_length=100)
deliveryManagedFrom = forms.CharField(label="Delivery Managed From", max_length=100)
location = forms.CharField(label="Location", max_length=100)
class AccountForm(ModelForm):
class Meta:
model = Account
fields = ['accountName','countryName', 'marketName', 'msdmName', 'deliveryManagedFrom', 'location']
views.py
from django.shortcuts import render
from django.views import generic
from .models import Account
from .forms import AccountForm
def index(request):
return render(request, 'personal/home.html')
# generic view to fetch the data then show in a list
class IndexView(generic.ListView):
# a name to refer to the object_list(to be used in the index.html)
context_object_name = 'account_list'
template_name = 'personal/index.html'
def get_queryset(self):
return Account.objects.all()
# generic view to show the details of a particular object
class DetailsView(generic.DetailView):
model = Account
template_name = 'personal/detail.html'
def makeentry(request):
if request.method == 'POST':
form = AccountForm(request.POST)
if form.is_valid():
accountName = request.POST.get('Account Name', '')
countryName = request.POST.get('Country Name', '')
marketName = request.POST.get('Market Name', '')
msdmName = request.POST.get('MSDM Name', '')
deliveryManagedFrom = request.POST.get('Delivery Managed From', '')
location = request.POST.get('Location', '')
account = Account(accountName=accountName, countryName=countryName, marketName=marketName, msdmName=msdmName, deliveryManagedFrom=deliveryManagedFrom, location=location)
account.save()
form = AccountForm()
return render(request, 'personal/makeentry.html', {'form': form})
else:
form = AccountForm()
return render(request, 'personal/makeentry.html', {'form': form})
makeentry.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Account Entry</title>
</head>
<body>
<form action="{% url 'makeentry' %}" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit">
</form>
</body>
</html>
detail.html
{% if account_list %}
<table>
<tr>
<td> Account Name </td>
<td> Country Name </td>
<td> Market Name </td>
<td> MSDM Name </td>
<td> Delivery Managed From </td>
<td> Location </td>
</tr>
{% for account in account_list %}
<tr>
<td>{{ account.accountName }}</td>
<td>{{ account.countryName }}</td>
<td>{{ account.marketName }}</td>
<td>{{ account.msdmName }}</td>
<td>{{ account.deliveryManagedFrom }}</td>
<td>{{ account.location }}</td>
</tr>
{% endfor %}
</table>
{% endif %}
I think you are making this harder than it needs to. You have a Form and a ModelForm of the same name. You should just be able to use the ModelForm. If there are attributes you want to pass with your ModelForm check out ModelForm Overriding default widgets. It has also been my experience to set action=“” and let the view handle the redirect on success.
def make_entry(request):
if request.POST:
form = AccountForm(request.POST)
if form.is_valid():
new_form = form.save()
return redirect('where-you-want-to-redirect ',
# View current saved info or change to what you want to show
pk=new_form.pk)
I am trying to post multiple values from different models in a for loop in a template. It is not doing what I am planning. I want to display a count of LeadActions that belong to Leads in a table. I did comment the part out that is not working as well. The table should display the list of Leads and the the count of how many overdue actions(LeadActions) there are for that specific lead.
My View
class LeadListView(LoginRequiredMixin, generic.ListView):
login_url = '/scrty/login/'
template_name = "nodiso/leadslist.html"
model = models.Leads
def get_context_data(self, **kwargs):
ctx = super(LeadListView, self).get_context_data(**kwargs)
ctx['actions']= models.LeadActions.objects.all()
return ctx
def get_queryset(self):
return models.Leads.objects.filter(company=self.request.session['compid'],archive=False)
My template
<table class="table">
<thead>
<th>Name</th>
<th>Overdue Tasks</th>
<th>Total Tasks</th>
</thead>
{% for lead in leads_list %}
{# {% for action in action_list %}#}
<tr>
<td>{{lead.name}}</td>
<td><span class="badge">{{ actions.name|length }}</span></td>
<td><span class="badge">42</span></td>
</tr>
{# {% endfor %}#}
{% endfor %}
</table>
The Models
class LeadActions(models.Model):
lead = models.ForeignKey(Leads)
name = models.CharField(max_length=265)
crdate = models.DateField(auto_now_add=True)
Duedate = models.DateField()
creator = models.CharField(max_length=265)
overdue = models.IntegerField(null=True,blank=True)
def __str__(self):
return self.name
class Leads(models.Model):
company = models.ManyToManyField(Company)
user = models.ManyToManyField(settings.AUTH_USER_MODEL)
name = models.CharField(max_length=265)
email = models.EmailField(max_length=265)
tel = models.IntegerField()
archive = models.BooleanField(default=False)
dateenq = models.DateField(auto_now_add=True,null=True)
def get_absolute_url(self):
return reverse('nodisoapp:leadlist')
def __str__(self):
return self.name
You shouldn't be sending the list of actions from the view. Instead, in the template, you can access {{ lead.leadactions_set.count }} to give the count of LeadActions related to each Lead in the loop.