I have a problem in django reverse many to many. Basically, I think I am missing something that I couldn't understand properly yet.
I have these models and views.
models.py
class TheorySyllabus(models.Model):
name = models.CharField(max_length=100, null=True, blank=True)
subject_duration = models.ManyToManyField(
SubjectDuration, related_name='subject_durations')
course_type = models.ForeignKey(
CourseType, on_delete=models.DO_NOTHING, null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
class Meta:
verbose_name_plural = 'Theory Syllabus'
class TheoryCourse(models.Model):
name = models.CharField(max_length=100)
student = models.ManyToManyField(Student, related_name='theory_courses')
theory_syllabus = models.ForeignKey(
TheorySyllabus, on_delete=models.DO_NOTHING, null=True, blank=True)
is_active = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
class Student(models.Model):
user = models.OneToOneField(CustomUser, on_delete=models.CASCADE)
first_name = models.CharField(max_length=200)
last_name = models.CharField(max_length=200)
date_of_birth = models.DateField()
fiscal_code = models.CharField(max_length=50)
phone = models.CharField(max_length=50)
license = models.ForeignKey(
License, on_delete=models.PROTECT, blank=True, null=True)
picture = models.ImageField(
blank=True, null=True, default='default.png')
id_card = models.ForeignKey(
IDCard, on_delete=models.PROTECT, blank=True, null=True)
address = models.CharField(max_length=100)
cap = models.CharField(max_length=10)
city = models.CharField(max_length=100)
province = models.CharField(max_length=100)
country = models.CharField(max_length=100)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
is_active = models.BooleanField(default=True)
def __str__(self):
return self.user.first_name + ' ' + self.user.last_name
views.py
class CourseListView(ListView):
model = TheoryCourse
queryset = TheoryCourse.objects.filter(
is_active=True).order_by('-created_at')
template_name = 'theory/course_list.html'
context_object_name = 'theory_courses'
paginate_by = 10
template
<div class="card-body table-responsive p-0">
<table class="table table-hover text-nowrap table-bordered">
<thead>
<tr>
<th>Course Type</th>
<th>Course Name</th>
</tr>
</thead>
<tbody>
{% for course in theory_courses %}
<tr>
<td>{{course.theory_syllabus.name}}</td>
<td>{{course.name}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
What I need to do, is to retrieve the total number of students that are in each TheoryCourse model. But I really have no idea how to use the reverse relationship.
I tried to use that in the template with something like:
{% for student in theory_courses.students.all %}
{% endfor %}
But, it's not working. I read all the django documentation but either I didn't understand something or I am doing something wrong.
Any help would be appreciated
So, you have student in your model, not students. Thus for will look something like this
{% for student in theory_courses.student.all %}
{% endfor%}
Furthermore, if you want to get only count, you can just use
{% for student_count in theory_courses.student.count %}
{% endfor %}
P.S. That has nothing to do with reverse (related_name) in many to many. related name just means that you can access your TheoryCourse model from Student with Student.theory_courses
Related
I would like to change the data that is in this column from a form but I can't display the data and save them and also add a delete button. anyone have a solution.
models.py
class Employe(models.Model):
Matricule = models.CharField(max_length=10, null=False)
Prenom = models.CharField(max_length=40, null=True)
Nom = models.CharField(max_length=40, null=True)
Tel = models.CharField(max_length=20, null=True)
Adresse = models.CharField(max_length=100, null=True)
Courriel = models.CharField(max_length=100, null=True)
Horaire = models.CharField(max_length=50, null=True)
Date_embauche = models.CharField(max_length=100, null=True)
UtilisateurOSP = models.CharField(max_length=100, null=True)
MotdepasseOSP = models.CharField(max_length=50, null=True)
Anciennete = models.CharField(max_length=10, null=True)
data_created = models.DateTimeField(auto_now_add=True, null=True)
class Disciplinaire(models.Model):
employe = models.ForeignKey(Employe, null=True, on_delete=models.SET_NULL)
Avis_verbal = models.CharField(max_length=300, null=True)
Avis_ecrit = models.CharField(max_length=300, null=True)
Avis_ecrit2 = models.CharField(max_length=300, null=True)
Suspension = models.CharField(max_length=300, null=True)
Fin_emploie = models.CharField(max_length=300, null=True)
data_created = models.DateTimeField(auto_now_add=True, null=True)
forms.py
class disciplinaireForm(ModelForm):
class Meta:
model = Disciplinaire
fields = '__all__'
views.py
def updateDisciplinaire(request, id):
emp = Disciplinaire.filter()
forms = disciplinaireForm(instance=emp)
if request.method == 'POST':
forms = disciplinaireForm(request.POST, instance=emp)
if forms.is_valid():
forms.save()
return redirect('/')
context = {'forms':forms}
return render(request, 'accounts/updateDisciplinaire.html', context)
page.html
<th scope="col">Avis Verbal</th>
<th scope="col">1er Avis Écrit</th>
<th scope="col">2e Avis Écrit</th>
<th scope="col">Suspension</th>
<th scope="col">Fin d'emploi</th>
<th scope="col">Action</th>
</tr>
{% for j in disci %}
<tr>
<td>{{j.Avis_verbal}}</td>
<td>{{j.Avis_ecrit}}</td>
<td>{{j.Avis_ecrit2}}</td>
<td>{{j.Suspension}}</td>
<td>{{j.Fin_emploie}}</td>
<td><a class="btn btn-outline-info" href="{% url 'updateDisciplinaire' j.id %}">Modifier</a>
</tr>
{% endfor %}
data and button
error message
The error says that in line 102 from your views.py you are trying to filter something. If you want to filter try:
emp_all = Disciplinaire.objects.filter(employe = id)
for emp in emp_all:
print(emp.Matricule)
you need to put how to filter, by which field.
When you use filter it will get you a queryset, a list of records not just one single record, if you want a single record you can use get:
emp = Disciplinaire.objects.get(employe = id)
I am trying to get a list of all categories and below each category the list of all related articles.
The problem is that I am getting the list of all articles under each category. I read documentation and few answers but nothing seems to be working and I am not sure where I am making the mistake.
models.py
class Category(models.Model):
title = models.CharField(max_length=75, default='', blank=False, null=False)
body = CharField(max_length=2000, default='', null=True, blank=True)
slug = models.SlugField(unique=True, blank=True)
publish = models.DateTimeField('publish', default=timezone.now)
class Meta:
ordering = ('-publish',)
verbose_name = 'category'
verbose_name_plural = 'categories'
get_latest_by = 'publish'
class Article(models.Model):
id = models.AutoField(primary_key=True)
author = models.ForeignKey(User, blank=True, null=True, on_delete=models.SET_NULL) #settings INSTALLED_APPS
title = models.CharField('title', max_length=200)
body = CKEditor5Field('Body', config_name='extends')
last_updated = models.DateTimeField(auto_now=True)
publish = models.DateTimeField('publish', default=timezone.now)
#tags = TagField(required=False, widget=LabelWidget)
category = models.ForeignKey(Category, on_delete = models.CASCADE, blank=True, related_name='category')
slug = models.SlugField(unique=True, blank=True)
views.py
#login_required
def hal_home(request):
top_categories = Category.objects.all()[:3]
category_related_articles = Article.objects.prefetch_related('category').all()
context = {
'category_related_articles': category_related_articles
}
return render(request, 'hal/homepage.html', context)
homepage.html
{% for category in top_categories %}
<div class="btn btn-light text-center text-justify">
<div>{{ category.title }}</div>
</div>
<br>
<p>{% for article in category_related_articles %}
{{article.title}}<br>
{% endfor %}</p>
{% empty %}
<div>No categories</div>
{% endfor %}
You should use prefetch_related with your category queryset.
And also I would suggest you to change the related_name to articles since category.articles.all() seems more readable and easier than category.category.all() .
category = models.ForeignKey(Category, on_delete = models.CASCADE, blank=True, related_name='articles')
Now you can change some code in your views and templates.
top_categories = Category.objects.prefetch_related("articles").all()[:3]
context = {'top_categories': top_categories}
Now you can get articles by category in template with:
{% for category in top_categories %}
{{category.title}}
# articles of each category
{% for article in category.articles.all %}
{{article}}
{% endfor %}
{% endfor %}
I am trying to print all the orders related to a specific customer. I used a for loop to access my orders in the html file, and i used an if statement to make sure that the order is related to the customer.
{% for order in orders %}
{% if customer.name == order %}
{{ order }}
{% endif %}
{% endfor %}
in my views I gave my html file access to these variables.
def orderss(request, pk):
Customer = customer.objects.get(id=pk)
orders = Order.objects.all()
context = {
'customer':Customer,
'orders': orders,
}
return render(request, 'Inventory_Management/orders.html', context)
to reach this page i used a button
View Orders
the url is the one below
path('orders/<str:pk>/', orderss, name="orderss")
related models
class Order(models.Model):
STATUS = (
('Pending', 'Pending'),
('Out for delivery', 'Out for delivery'),
('Delivered', 'Delivered'),
)
order_head = models.ForeignKey(order_header, blank=False, null=True, on_delete=models.SET_NULL)
items = models.ForeignKey(item, blank=False, null=True, on_delete=models.SET_NULL)
Quantity = models.CharField(max_length=100)
date_created = models.DateTimeField(auto_now_add=True, null=True)
total = models.CharField(max_length=100)
status = models.CharField(max_length=200, null=True, choices=STATUS)
def __str__(self):
return '{self.order_head.Buyer}'.format(self=self)
class customer(models.Model):
name = models.CharField(max_length=12, blank=False)
phone = models.CharField(max_length=12, blank=False)
email = models.CharField(max_length=50, blank=False)
date_created = models.DateTimeField(auto_now_add=True, null=True)
def __str__(self):
return self.name
class order_header(models.Model):
date_created = models.DateTimeField(auto_now_add=True, null=True)
User = models.CharField(max_length=100, blank=False, default="Seller")
Type = models.CharField(max_length=100, default="cash")
Buyer = models.ForeignKey(customer, blank=True, null=True, on_delete=models.SET_NULL)
Note = models.CharField(max_length=100, blank=True, default="Discount: ")
Order_Id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
def __str__(self):
return 'Order Customer: {self.Buyer}, Order Id: {self.Order_Id}'.format(self=self)
now the problem is no orders appear when I press the button, all i get is a blank page even though the specific customer has a number of orders. Help appreciated! Please Help!
In template you're trying to compare name field that is string with object (Order). I guess you thought that name will be compared with order string representation using __str__ method.
Try this:
views.py
Customer = customer.objects.get(id=pk)
orders = order_header.objects.filter(Buyer=Customer)
context = {'orders': orders}
template
{% for order_head in orders %}
{% for order in order_head.order_set.all %}
{{ order }}
{% endfor %}
{% endfor %}
In my Django App, I have 2 models. One called Post and one called Categories. When a user clicks on a category, I want only the posts that are in that category to appear in the category detail view. For example if a user clicks on the medical category, I only want the posts in the medical category to appear.
Models:
class Category(models.Model):
title = models.CharField(max_length=200)
colorcode = models.CharField(max_length=20, blank=True, null=True)
description = models.TextField()
image = models.ImageField(blank=True, null=True)
slug = models.SlugField(unique=True)
class Post(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
title = models.CharField(max_length=200)
text = models.TextField()
sub_description = models.TextField(blank=True, null=True)
created_date = models.DateTimeField(default=timezone.now)
published_date = models.DateTimeField(blank=True, null=True)
category = models.ForeignKey(Category, on_delete=models.CASCADE, blank=True, null=True)
image = models.ImageField(blank=True, null=True)
live = models.BooleanField(default=False)
slug = models.SlugField(unique=True)
Views:
class CategoryDetailView(DetailView):
model = Category
def get_context_data(self, **kwargs):
context = super(CategoryDetailView, self).get_context_data(**kwargs)
context['category_posts'] = Post.objects.filter(live=True)
return context
Template:
{% for post in category_posts %}
<div class="post">
<div class="post-title">
{{ post.title }}
</div>
<div class="post-author">
{{ post.author }}
</div>
</div>
{% endfor %}
In a DetailView, you have access to the actual object being rendered (in your case the Category instance) through self.object.
So in your get_context_data method you can do:
context['category_posts'] = Post.objects.filter(live=True, category=self.object)
Note that self.object might be None so you may want to deal with that case.
I have two models that feed one view.
models.py
class Item(models.Model):
item_name = models.CharField(max_length=100)
item_type = models.ForeignKey(Item_type, on_delete=models.SET_NULL, null=True)
owned_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)****
added_at = models.DateTimeField('date item added')
updated_at = models.DateTimeField('last update')
def __str__(self):
return self.item_name
class Item_status(models.Model):
item = models.ForeignKey(Item, on_delete=models.SET_NULL, null=True)
borrower = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
loaned_at = models.DateTimeField(default=None, blank=True, null=True)
due_back = models.DateTimeField(default=None, blank=True, null=True)
def __time__(self):
return self.loaned_at
def itemname(self):
return (self.item.item_name)
I have the following view
views.py
class LoanedItemsByUserListView(LoginRequiredMixin,generic.ListView):
model = Item_status
template_name ='catalog/item_status_list_borrowed_user.html'
paginate_by = 10
def get_queryset(self):
return Item_status.objects.filter(borrower=self.request.user).order_by('due_back')
def get_context_data(self, **kwargs):
context = super(LoanedItemsByUserListView, self).get_context_data(**kwargs)
context['Owned_list'] = Item.objects.filter(owned_by=self.request.user, item_type = 1)
context['Loaned_list'] = Item_status.objects.exclude(borrower=self.request.user).exclude(borrower__isnull=True)
return context
I would like to find the cross section of the 'Owned_list' and the 'Loaned_list' in a single template
Something like
<h2>Loaned Books</h2>
{% if Owned_list %}
<ul>
{% for thing in Owned_list.item_name and in Loned_list.item.item_name %}
<li>
{{thing}}
</li>
{% endfor %}
</ul
{% else %}
<p>There are no books in the library.</p>
{% endif %}
I have take a look at the django documentation here https://docs.djangoproject.com/en/1.11/topics/class-based-views/generic-display/, and around SO but not found exactly what I am looking for.
Thanks!