Django: Accessing full User information via ManyToMany field - django

everyone- I'm new to Django and working on my first big project and I'm having trouble with accessing default Django User model information via a ManyToMany relationship. I've spent a great deal of time searching and can't crack it.
models.py
class Event(models.Model):
event_name = models.CharField(max_length=200, null=True, unique=True)
#etc...
class School(models.Model):
user = models.ManyToManyField(User)
event = models.ForeignKey(Event, null=True, on_delete=models.PROTECT)
#etc...
My url contains the id of the Event, so...
views.py
def schools(request, pk):
event = Event.objects.get(id=pk)
school = School.objects.filter(event=event)
return render(request, 'accounts/schools.html', {'event':event, 'school':school})
template
{% for school in school %}
<tr>
<td>{{school.name}}</td>
<td>{{school.user.all}}</td>
{% endfor %}
On my template, I'm able to use {{school.user.all}} to get me a Queryset displayed with the username of each User, but I want the first_name and last_name and can't see to figure out how to get that..
Thank you for any suggestions. I greatly appreciate your time!

You should include both schools and users to your context.
You can do this with a dictionary. Add each school as a key, and users of each school as its values. Then you can pass this dictionary to your template.
View function:
def schools(request):
school_dict = dict()
schools = School.objects.all()
for school in schools:
school_dict[school] = school.user.all()
return render(request, 'accounts/schools.html', {'schools': school_dict})
And in your template:
{% for school, users in schools.items %}
<h3>{{ school.title }}</h3>
<table>
{% for user in users %}
<tr>
<td>{{ user.first_name }}</td>
<td>{{ user.last_name }}</td>
</tr>
{% endfor %}
</table>
{% endfor %}

I was able to add this to my school model to get what I wanted:
def director(self):
test = ",".join([str(p) for p in self.user.all()])
user = User.objects.get(username=test)
return user.first_name + " " + user.last_name
HOWEVER: if there is more than one user associated with "School" it displays blank

Related

Django, Unable to view certain database information

I've been working on a project and I've been stuck for over a week and haven't been able to find the solution to this problem.
I'm creating a school management app. I've successfully allowed the teachers to create a schedule, allowed the students to view it and select it as part of their class. The problem I'm running into is that the teacher is not able to see the students information after they've chosen a class.
For models I have:
class Student(models.Model):
user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)
englishName = models.CharField(max_length=200)
studentName = models.CharField(max_length=200)
studentId = models.CharField(max_length=200)
birthday = models.DateField()
gender = models.CharField(max_length=6)
gradeLevel = models.CharField(max_length=8)
since = models.DateField()
duration = models.CharField(max_length=3)
contactNumber = models.CharField(max_length=13, default=00000000)
email = models.EmailField(max_length=200, default='address#email.com')
def __str__(self):
return self.studentName
def index(request):
data=Student
context = {'form': data}
return render(request, 'student-information.html', context)
class Schedule(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
date = models.DateField(null = True, blank = True)
time = models.TimeField(null = True, blank = True)
duration = models.TextField(null = True, blank = True)
capacity = models.PositiveSmallIntegerField(default=1)
student = models.ForeignKey(Student, null = True, on_delete=models.CASCADE)
def __datetime__(self):
return self.date + '' + self.student
def index(request):
data = Schedule
context = {'form': data}
return render(request, 'set-schedule.html', context)
For my views file I have:
#login_required
#allowed_users(allowed_roles=['teacher'])
def dailySchedule(request):
today = datetime.now().date()
schedules = Schedule.objects.filter(date=today)
students = []
for schedule in schedules:
students.append(schedule.student)
context = {'today': datetime.now().date(), 'schedules': schedules, 'students': students}
return render(request, 'eslbeeph/daily-schedule.html', context)
and for the html file I have:
{% extends 'main.html' %}
{% block content %}
<div class="container-fluid">
<div class="daily-schedule-title">
<h3 class="daily-schedule-header">Schedule</h3>
</div>
<!--Information to be obtained by from the database.-->
<div class="daily-schedule-table">
<table class="daily-schedule">
<tr>
<th>Date</th>
<th colspan="6">{{ today|date:"F d, Y" }}</th>
</tr>
<tr>
<th>Start Time</th>
<th>Account</th>
<th>Duration</th>
<th>Student ID</th>
<th>Student Name</th>
<th>Class Status</th>
<th>Student Profile</th>
</tr>
{% for schedule in schedules %}
<tr>
<td>{{ schedule.time|date:"H:i" }}</td>
{% for student in students %}
<td>{{ schedule.student.user.username }}</td>
<td>{{ schedule.duration }}</td>
<td>{{ schedule.student.studentId }}</td>
<td>{{ schedule.student.englishName }}</td>
{% endfor %}
<td>{ status }</td>
<td></td>
</tr>
{% endfor %}
</table>
</div>
</div>
{% endblock content %}
Now, There's a lot more code to the project but these are the areas I think are causing the problem. I've tried a number of different things to get this to work, but nothing's worked.
If anyone can see where I'm going wrong or what I need to do let me know. I appreciate any help anyone can give me.
What I've been trying to do is get the a table to show up with the schedule time, the user name of the student who selected the schedule, the number of minutes the teacher stated the class would be, the students id number, and the students english name. The class status and the button for the students profile I plan to handle later.
Right now the time and the class length show up fine. But no matter what I do I cannot get the students user name, english name, and ID to populate at all.
Any tips, examples, or guesses as to why this is happening would be appreciated.
EDIT
After doing a bit more work I found that the Student model is not connecting to the Schedule model. So, the problem is different from what I originally suspected. It's not that the student information isn't being shown. It's that the schedule a student selects isn't recognizing the student has selected it.

Working with checkboxes and querying the database in Django

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?

how to display many to many field properly in django

This code saves the data and displays the data as i wanted.but while displaying courses it displays like this , ]> .It displays with
QuerySet[].i only want the courses name to be displayed.How can i do that
models.py
class Teacher(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=50)
phone = models.CharField(max_length=15)
email = models.EmailField()
image = models.ImageField(upload_to='Teachers',blank=True)
courses = models.ManyToManyField(Course)
views.py
def viewteacher(request):
teachers = Teacher.objects.all().order_by('-joined_date')
year1 = datetime.datetime.today().year
return render(request,'students/view_teacher.html',{'teachers':teachers,'year_list':range(2016,year1+1)})
template
{% for teacher in teachers %}
<tr>
<td>{{teacher.name}}</div></td>
<td>{{teacher.courses.all}}</td>
<td>{{teacher.address}}</td>
<td>{{teacher.phone}}</td>
<td>Profile</td>
<td>Edit</td>
<td>Delete</td>
</tr>
{% endfor %}
</tbody>
A QuerySet is rendered like <QuerySet [ ... ]>, so you can iterate over the queryset, and render it properly, like:
{% for teacher in teachers %}
<tr>
<td>{{teacher.name}}</div></td>
<td>{% for course in teacher.courses %} {{course.name}} {% endfor %}</td>
<td>{{teacher.address}}</td>
<td>{{teacher.phone}}</td>
<td>Profile</td>
<td>Edit</td>
<td>Delete</td>
</tr>
{% endfor %}
Obtain the list of courses for every individual teacher is however not very efficient. You can use .prefetch_related to speed up the process. It will then perform a limited number of queries to fetch all the courses, and link these properly to the correct teacher(s):
def viewteacher(request):
teachers = Teacher.objects.prefetch_related('courses').order_by('-joined_date')
year1 = datetime.datetime.today().year
return render(
request,
'students/view_teacher.html',
{'teachers':teachers,'year_list':range(2016,year1+1)}
)

Django Template Tagging inserting a single value from a ListView

So I am undertaking a website project and I am having some issues with one page.
I essentially load NBA teams wins and losses onto a page and make my own makeshift standings ladder.
The data loaded from my model is as follows:
MODEL.PY
from django.db import models
from django.utils import timezone
# Create your models here.
class Team(models.Model):
team_name = models.CharField(max_length=500, unique=True, primary_key=True)
wins = models.PositiveIntegerField()
losses = models.PositiveIntegerField()
created_date = models.DateTimeField(default=timezone.now)
I use the ListView in my views.py file as follows:
VIEWS.PY
class LadderListView(LoginRequiredMixin, ListView):
#this defaults to looking for the models name html so in this case team_list.html
# so i changed it to template_name variable
template_name = 'merchbet/ladder_list.html'
model = models.Team
and render the urls.py file as follows:
path('ladder/', views.LadderListView.as_view(), name='ladder_list'),
all of this successfully works.
When I get to my html code I am able to the teams, and their win/loss records to print to the website with template tagging, but I am looking to inject one line at the bottom which shows the "Last Updated: {{ team.created_date }}.
This is not working and I am not getting an errors, the "{{ team.created_date }}" just shows nothing on the url page.
I have looked through the docs and can not see what I am doing wrong.
This is my html code:
LADDER_LIST.HTML
{% extends 'merchbet/base.html' %}
{% block content %}
<div class="container">
<table>
<tbody>
<tr>
<td>Team</td>
<td>Wins</td>
<td>Losses</td>
</tr>
{% for teams in object_list %}
<tr>
<td>{{ teams.team_name }}</td>
<td>{{ teams.wins }}</td>
<td>{{ teams.losses }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<h2 style="color:white;"> testing {{ team.created_date }}</h2>
{% endblock %}
Thanks for any help in advance.
You don't have anything called team in your template.
If you just want to display the value from a single team in the lst, and don't care which one, just grab the first or last:
{{ object_list.0.created_date }}
you just need to edit your models and that should fix your problem
class Team(models.Model):
....
created_date = models.DateTimeField(auto_now=False, auto_now_add=True) #when you first add team
updated = models.DateTimeField(auto_now=True, auto_now_add=False) #when you update
class Meta :
ordering = ["-updated","created_date"]

How to get a value from related object in a django template

I'm quite new with python and django and I apologize if the topic was already covered, but I coudln't find an answer to my question.
I have theese classes in my models.py
class Category(models.Model):
category_type = models.CharField(max_length=50)
description = models.TextField()
def __unicode__(self):
return self.category_type
class Area(models.Model):
area_type = models.CharField(max_length=50)
description = models.TextField()
def __unicode__(self):
return self.area_type
class Topic(models.Model):
topic_type = models.CharField(max_length=50)
description = models.TextField()
def __unicode__(self):
return self.topic_type
class Tag(models.Model):
tag_type = models.CharField(max_length=50)
description = models.TextField()
def __unicode__(self):
return self.tag_type
class GenericRecord(models.Model):
document_title = models.CharField(max_length=500)
category = models.ForeignKey("Category")
area = models.ForeignKey("Area")
topic = models.ForeignKey("Topic")
tag = models.ForeignKey("Tag")
note = models.TextField(null=True, blank=True)
link = models.TextField(null=True, blank=True)
file_upload = models.FileField(upload_to='GenericRecord/', null=True, blank=True)
class Meta:
abstract = True
class Document(GenericRecord):
code = models.CharField(max_length=500, null=True, blank=True)
reference = models.CharField(max_length=500)
issue_date = models.DateField(auto_now=False, auto_now_add=False)
validation_date = models.DateField(auto_now=False, auto_now_add=False, null=True, blank=True)
def get_admin_url(self):
return reverse("admin:%s_%s_change" % (self._meta.app_label, self._meta.model_name), args=(self.id,))
def __unicode__(self):
if self.code:
return "%s-%s" % (self.code, self.document_title)
else:
return "--%s" % self.document_title
And this piece of code in views.py
def documents_list(request):
# Generate counts of some of the main objects
num_docs=Document.objects.all().count()
docs=Document.objects.all()
num_articles=Article.objects.all().count()
articles=Article.objects.all()
template='documents_management.html'
for object in docs:
object.fields = dict((field.name, field.value_to_string(object)) for field in object._meta.fields)
# Render the HTML template documents_management.html with the data in the context variable
return render(request,template, context={'docs':docs, 'num_docs':num_docs,'docs':docs, 'num_articles':num_articles, 'articles':articles})
In the template I'm trying to get a table with all the values, but for the related objects I get the primary key (of course).
Here is the code in my template:
<table class="w3-table-all">
{% for object in docs %}
{%if forloop.first %}
<tr>
{% for field, value in object.fields.iteritems %}
<th>{{ field }}</th>
{% endfor %}
</tr>
{%endif%}
{% endfor %}
{% for object in docs %}
{% for field, value in object.fields.iteritems %}
<td>{{ value }}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
What I see in my browser
My question is, how can I get the object Category, Area etc... in order to get the category_type, area_type etc. value?
Thanks!
Here is an great example from the docs: https://docs.djangoproject.com/en/1.11/intro/tutorial03/#use-the-template-system
What you are searching for is the question.choice_set.all part.
UPDATE due to a hint of bad style
As mentioned by daniel you should ditch the Field.to_value_string method.
Since I am not a fan of implicit code I always recommend to code templates as explicit as possible, here would by my version of your template
<table class="w3-table-all">
{% for doc in docs %}
{% if forloop.first %}
<tr>
<th>Document Title</th>
<th>Category Type</th>
<th>Area Type</th>
<th>...</th>
</tr>
{% else %}
<tr>
<td>{{ doc.document_title }}</td>
<td>{{ doc.category.category_type }}</td>
<td>{{ doc.area.area_type }}</td>
<td>...</td>
</tr>
{% endif %}
{% endfor %}
</table>
What I changed:
only one for loop, you started with the if forloop.first you might also finish with the else case
refactored object to doc because objects is used often within django for model managers
add the fields explicit doc.area.area_type, this will prevent a new field in the model to also appear in the template but here I recommend an explicit over an implicit coding style
Also you can remove this from document_list:
for object in docs:
object.fields = dict((field.name, field.value_to_string(object)) for field in object._meta.fields)
The problem is in your use of Field.value_to_string. As the docstring on that method shows, this is for serialization, not for displaying values.
A much simpler and more effective way of doing this would be to use getattr, which gets the actual value; the template will then take care of converting those to a string, which in the case of the foreign keys will call the __unicode__ method of the related objects.
object.fields = dict((field.name, getattr(obj, field.name)) for field in object._meta.fields)