Here is the queryset:
researches = Graph.objects.filter(subject=subject_object).exclude(type='infografik').values_list('name', flat=True).distinct()
When I do:
{% for research in researches %}
in my template, the code in between executes the right amount of times, but for example {{ research.name }} doesn't work.
How to I access the object's attributes?
Thanks.
edited:
Graph model
name = models.CharField(max_length=100)
research = models.ForeignKey('Research')
explanation = models.TextField(max_length=1000)
path_to_file = models.CharField(max_length=100)
type = models.CharField(max_length=30, choices=type, null=True, blank=True)
subject = models.ManyToManyField(Subject)
thumbnail = models.ImageField(upload_to='thumbnails/', null=True, blank=True)
slug = models.SlugField(max_length=120, unique=True)
From the doc:
Each tuple contains the value from the respective field passed into the values_list()
So to print research names just do :
{% for research in researches %}
{{ research }}
{% endfor %}
Because you are asking for a flat list of values, there are no attributes to access. If you want access to all of the attributes, use either this query researches = Graph.objects.filter(subject=subject_object).exclude(type='infografik').distinct() which will return a queryset that can be iterated over or this one researches = Graph.objects.filter(subject=subject_object).exclude(type='infografik').values().distinct() which will return a list of dicts. In django's template language, you can access attributes in both like so:
{% for research in researches %}
{{ research.name }}
{{ research.author }}
...
{% endfor %}
The only way I know of to also get distinct objects is to use raw sql:
researches = Graph.objects.raw('SELECT * FROM appname_graph WHERE subject_id = %s AND type <> %s GROUP BY name', [subject_object.id, 'infografik'])
Related
I have an intermediate models connection
Simplified:
class Person(models.Model):
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
etc...
class Company(models.Model):
name = models.CharField(max_length=60)
etc...
class CompanyEnrollment(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
company = models.ForeignKey(Company, on_delete=models.CASCADE)
company_position =
models.ForeignKey(CompanyPosition,on_delete=models.CASCADE)
etc...
class Meta:
unique_together = [['person', 'company']]
class CompanyPosition(models.Model):
name = models.CharField(max_length=60)
I want to create the following array:
datas = Person.objects.All(...{All elements of Person model supplemented with CompanyPosition_name}...)
There is a case where a person does not have a company_name association
Is it possible to solve this with a query?
If you have an explicit through model for your many-to-many relationship, you could use this to only get or exclude based on the entries of this table, using an Exists clause:
enrollments = CompanyEnrollment.objects.filter(person_id=OuterRef('pk'))
enrolled_persons = Person.objects.filter(Exists(enrollments))
unenrolled_persons = Person.objects.filter(~Exists(enrollments))
If you don't have an explicit intermediate table, then it's has been generated by Django directly. You should be able to use it by referring to it with Person.enrollments.through instead of CompanyEnrollment.
Since you did not detailed much the CompanyEnrollment table, I assumed you're in the second case.
This is not the best solution in my opinion, but it works for now, with little data. I think this is a slow solution for a lot of data.
views.py I will compile the two necessary dictionaries
datas = Person.objects.all().order_by('last_name', 'first_name')
companys = CompanyEnrollment.objects.all()
Use Paginator
p = Paginator(Person.objects.all(), 20)
page = request.GET.get('page')
pig = p.get_page(page)
pages = "p" * pig.paginator.num_pages
Render HTML:
context = {
"datas": datas,
"pig": pig,
"pages": pages,
"companys": companys,
}
return render(request, "XY.html", context)
HTML template:
{% for datas in pig %}
{{datas.first_name}} {{datas.last_name}}
{% for company in companys %}
{% if datas == company.person %}
{{company.company.name}} <br>
{% endif %}
{% endfor %}
{% endfor %}
not the most beautiful, but it works ... I would still accept a more elegant solution.
I am trying to perform a query via a join.
My models.py looks like:
class TSFH(models.Model):
sB = models.DateTimeField(null=True)
sE = models.DateTimeField(null=True)
FKToUser = models.ForeignKey(User,default=None, on_delete=models.PROTECT)
class Tld(models.Model):
dNm = models.CharField(verbose_name="",max_length=40,unique=True)
FKToUser = models.ForeignKey('auth.user', default=None, on_delete=models.PROTECT)
class TSF(models.Model):
FKToT = models.ForeignKey('T', on_delete=models.PROTECT)
FKToTSFH = models.ForeignKey('TSFH', on_delete=models.PROTECT, null=True, blank=True)
views.py
enteredd = request.GET.get('d', '')
query=TSFH.objects.filter(FKToT__dNm=enteredd,FKToUser=request.user,sE__isnull=False)
return render(request, 'view.html', {'q':q})
templates/file.html
{% if q %}
{% for res in q %}
<li><span>{{ res.sE }}</span></li>
{% endfor %}
{% else %}
{% endif %}
When I view this all it complains about:
Cannot resolve keyword 'FKToT' into field
In plain sql I'm looking to perform the following just with dNm search directly from the enteredd instead of a hardcoded value of 123.145.23.1 as shown below:
SELECT sE
FROM tsfh, tsf, t
where
tsfh.id=tsf.FKTotsfh_id
and
t.id=tsf.FKToT_id
and
tsfh.sE is not null
and
t.dNm='123.145.23.1';
How can I keep these existing checks in the query but include this FKToT__dNm=enteredd somehow?
Thank you very much.
Do a little modification at this line:
query=TSFH.objects.filter(TST__FKToT__dNm=......)
If you put this meta into your class, it will specifically name the table.
class Meta:
db_table = '<your_table_name>'
You can read more here.
Is there a way to filter related objects in a class. I am not talking about filtering BY related objects but instead filtering the related objects themselves IN a class. Perhaps an example would better illustrate:
Say I have the following model:
class Book(models.Model):
title = models.CharField(max_length=200)
author = models.ForeignKey('Author', null=True)
isbn = models.CharField('ISBN',max_length=13)
genre = models.ManyToManyField(Genre)
class Genre(models.Model):
name = models.CharField(max_length=200)
...
class Author(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
date_of_birth = models.DateField(null=True, blank=True)
date_of_death = models.DateField('Died', null=True, blank=True)
I know how to do the straightforward filtering like getting all books for a specific genre:
books = Books.objects.filter(genre=1)
and then looping through this in the view:
{% for book in books %}
{{book.title}}
{% endfor %}
But, is there a way to filter a queryset's related objects? Let's say I have an already filtered author queryset and I ONLY want to list his books FROM a specific genre:
If I do this:
{% for book in author.books_set.all %}
{{book.title}}
{% endfor %}
I get ALL of his books (as I would expect and want).
But, is there a way to do something like this:
{% for book in author.books_set.filter(genre=1) %}
{{book.title}}
{% endfor %}
so that I am only getting a filtered list of the related objects?
I would prefer to do this in the view or as a class method as I do not like mixing logic in the template.
i.e.:
{% for book in author.books.filtered_genres %}
{{book.title}}
{% endfor %}
But, I cannot seem to figure out the best and most pythonic (or djangonic :) ) way to do this.
I know I can 'build' a data structure myself in a view by looping through the various querysets and building what I want but I was looking to preserve the data model and relationships already defined.
Any thoughts on what I am trying to accomplish? Or can I better elaborate on what I am trying to do?
Thanks!
You can apply or concatenate multiple filters in querysets on the Book model:
books = Books.objects.filter(author='Bob', genre=1)
or
books = Books.objects.filter(author='Bob').filter(genre=1)
or - if you want to queryset related objects - you can use prefetch_related method:
author_genre_books = Author.objects.filter(author='Bob').prefetch_related(book_set__genre=1)
#Doru:
I could not get this to work, got an error for
auths = Author.objects.filter(author='Bob').prefetch_related(book__genre=1)
TypeError: prefetch_related() got an unexpected keyword argument 'book__genre'
But, you put me on the right path!! I found the Prefetch method in the docs.
This is what I did and got it working as I needed:
auths = Author.objects.filter(author='Bob').prefetch_related(Prefetch('book_set', queryset=Book.objects.filter(genre=3), to_attr='filtered_books'))
then just used the following in template:
{% for book in author.filtered_books %}
{{book.title}}
{% endfor %}
So, thanks for putting me on to the right path!
I've got the following Django many-to-many through model setup, but I can't seem to figure out how to iterate through each Container, get the list of checkboxes and if those checkboxes are true or false (CheckboxStatus.status).
The models are:
class Container(models.Model):
name = models.CharField(max_length=200)
checkboxes = models.ManyToManyField('Checkbox',
through='CheckboxStatus',
related_name='containers')
class Checkbox(models.Model):
name = models.CharField(max_length=60)
description = models.CharField(max_length=200)
order = models.PositiveSmallIntegerField(default=0)
class CheckboxStatus(models.Model):
container = models.ForeignKey(Container,
related_name='checkboxstatus')
checkbox = models.ForeignKey(Checkbox, related_name='checkboxstatus')
status = models.NullBooleanField()
I've got the following where object_list = the CheckboxStatus model ...
{% for object in object_list. %}
{{ object.container }}
{{ object.checkbox }}
{{ object.status }}
{% endfor %}
... but this results in all checkboxes, and I need to do some operations on each Container. In pseudocode, I'd like to have:
for container in object_list (where objectlist is "container"):
container.id
container.checkbox.id
container.checkbox.status (unique for the container.id)
But maybe the relation is just plain wrong. Can some one push me in the right direction?
If I'm understanding this right, I don't think you need the through table. You should be able to define the ManyToManyField and then use a ModelForm and a CheckboxSelectMultiple widget to display the options as checkboxes.
I changed the models to:
class Container(models.Model):
name = models.CharField(max_length=200)
options = models.ManyToManyField('Option')
# I changed the name of the Checkbox model to Option, for clarity.
class Option(models.Model):
name = models.CharField(max_length=60)
description = models.CharField(max_length=200)
order = models.PositiveSmallIntegerField(default=0)
from forms.py:
class ContainerOptionsForm(forms.ModelForm):
class Meta:
model = Container
fields = ['options']
widgets = {
'options': forms.CheckboxSelectMultiple(),
}
Include the options form field in your template:
{{ form.options }}
If you need more control over the display of the options checkboxes, you can iterate over the options field of the form:
{% for checkbox in form.options %}
<label>{{ checkbox.choice_label }} {{ checkbox.tag }}</label>
{% endfor %}
This should take care of it for a single container on a page. If you need to handle multiple containers on the same page, you will need to look into ModelFormSet.
I fixed it.
Model code:
class ContainerBox(models.Model):
name = models.CharField(max_length=200)
class CheckBox(models.Model):
name = models.CharField(max_length=60)
containerbox = models.ManyToManyField(
ContainerBox, through="CheckBoxStatus")
class CheckboxStatus(models.Model):
containerbox = models.ForeignKey(ContainerBox, on_delete=models.CASCADE)
checkbox = models.ForeignKey(CheckBox, on_delete=models.CASCADE)
status = models.NullBooleanField()
and template code:
{% for containerbox in object_list %}
<h2>name: {{containerbox.name}}</h2>
{% for checkboxstatus in containerbox.checkboxstatus_set.all %}
{{ checkboxstatus.status}} ({{ checkboxstatus.checkbox }})<br/>
{% endfor %}
{% endfor %}
This does what I need it to do: iterate over containers, then over checkboxes. I just swapped checkboxes and checkboxstatuses.
I am trying to use prefetch_related’s new Prefetch option to further filter a database query. Using debug toolbar I can see that prefetch_related is doing its job in making the correct number of queries. However, one of those queries should be filtered to the current user, and I can see that it is not.
The goal of the below code is to show a list of Chapters. For each chapter, show its lessons. For each lesson, show the logged in user’s status (complete/incomplete).
The code that appears to not be working is in the view (setting the ‘chapters’ value).
Models:
class Chapter(models.Model):
status = models.IntegerField(choices=STATUS_CHOICES, default=1)
name = models.CharField(max_length=100)
slug = AutoSlugField(populate_from='name')
desc = models.TextField()
class Lesson(models.Model):
name = models.CharField(max_length=100)
chapter = models.ForeignKey(Chapter, related_name=‘les_chapter’)
class LessonStatus(models.Model):
status = models.IntegerField(choices=STATUS_CHOICES, default=1)
lesson = models.ForeignKey(Lesson, related_name="status_lesson")
student = models.ForeignKey(User)
chapter = models.ForeignKey(Chapter, related_name=“status_chapter")
View
def chapter_list(request, course_slug):
course = Course.objects.get(slug=course_slug)
chapters = Chapter.objects.filter(course=course).prefetch_related(
Prefetch('status_chapter__lesson__chapter', queryset=LessonStatus.objects.filter(student=request.user)),
)
return TemplateResponse(request,
'course/chapter_list_parent.html',
{'chapters': chapters, 'course': course,}
)
Template
<div id="chapters">
{% for ch in chapters %}
<p>{{ ch.name }}</p>
{% for le in ch.status_chapter.all %}
<p>lesson status: {{ le.status }}</p>
<p>lesson name: {{ le.lesson.name }}</p>
{% endfor %}
{% endfor %}
</div>
When I run this code the LessonStatus is not being filtered by student=request.user. Instead, it is simply getting all LessonStatus records including those that are for other users.
Found the solution. I was structuring the 'chapter's queryset incorrectly. Here's what worked in the end:
chapters = Chapter.objects.filter(course=course).prefetch_related(
Prefetch('recchapter', queryset=LessonRec.objects.filter(student=student).select_related('lesson').order_by('lesson')),
)