Not expected django query set response - python

I'm making a query set with django to list some courses. The problem is when I make the query in the django shell, it returns something like this: <QuerySet [<Course: Course object (1)>,....]>
How can I make it to obtain the table information?
PSD: I make a query set with the users table exactly as I described and I get the expected result. But it can't show the result in the template. So if you can help... Thanks for the help in advance.
class ListCursos( TemplateView):
model1 = User
model2 = Course
template_name = 'plantillas/miscursos.html'
def get_context_data(self, *args, **kwargs):
context = super(ListCursos, self).get_context_data(**kwargs)
context['usuarios'] = User.objects.all()
context['cursos'] = Course.objects.all()
return context

The values of the columns for each instance of a model are as stored as instances variables. You have not provided the definition of one of your models, so I'll just take this for an example.
class Course(models.Model): # example model
name = models.CharField(max_length=10)
students = models.IntegerField()
When you have a queryset of Course models you can access them by index
>>> all_courses = Course.objects.all()
<QuerySet [<Course: Course object (1)>]>
>>> first_course = all_courses[0]
and to acess the values of the selected Course model instance you just type the names for the columns that you have in the class definition. if for example you have the Course model with name history and 10 students then
>>> first_course.name # just type the name of the column
'history'
>>> first_course.students
10
So to access them in a django template, considering that you are passing in the context the Course.objects.all() with a key of "cursos". (like you are doing)
{% for course in cursos %}
<div>{{course.name}}</div>
<div>{{course.students}}</div>
{% endfor %}

Related

How to pass a variable to class based views (ListView)

My Views.py code
class ListaFuncionariosView(ListView):
model = Funcionarios
template_name = '../templates/funcionarios/lista_funcionarios.html'
paginate_by = 10
ordering = ['FuncionarioCartao']
queryset = Funcionarios.objects.filter(EmpresaCodigo=1)
funcionarios_number = Funcionarios.objects.aggregate(Count('FuncionarioCartao'))
My HTML
<h1>Good Morning</h1>
Exists: {{funcionarios_number}}
<br>
{{funcionarios}}
I would like to show the total number of registered employees in my db table (in the HTML file below), but I don't know how to put variables in class based views, in this case ListView. I'm using 4.0 Django
I tried put: funcionarios_number = Funcionarios.objects.aggregate(Count('FuncionarioCartao')) in bellow of my class, but this is not showed in my html.
By aggregating at the class-level, the query will run when you start the server, and the count will thus always remain that exact number.
You can define this in a function:
class ListaFuncionariosView(ListView):
model = Funcionarios
template_name = '../templates/funcionarios/lista_funcionarios.html'
paginate_by = 10
ordering = ['FuncionarioCartao']
queryset = Funcionarios.objects.filter(EmpresaCodigo=1)
def funcionarios_number(self):
return Funcionarios.objects.aggregate(total=Count('FuncionarioCartao'))[
'total'
]
and then access the function in the view in the template:
{{ view.functionarios_number }}

Make the number of rows after narrowing-down

This is my serializer.
class MixSerializer(serializers.ModelSerializer):
pub_date = serializers.DateTimeField(format="%m/%d/%Y,%I:%M:%S %p")
new_order = #I want to get the number order
class Meta:
model = Mix
fields = ('id','pub_date','detail','user','u_key')
And I narrowing-down the rows like this below.
def get_queryset(self):
queryset = Mix.objects.all()
u_key = self.request.query_params.get('u_key')
if u_key is not None:
queryset = queryset.filter(u_key=u_key)
return queryset
For example, it returns the 30 items from 100 items.
so id should be (1,4,5,6,9,11,13...) like this,
However I want to get the number new_order (1,2,3,4,5,6,....)
I guess I should do some trick in Serializer?
or any other way ?
Any help appreciated.
Well ID is the actual ID in the database, which you don't want to change or override in your queryset (or elsewhere such as your template) because then you would be referring to a different model object, which will cause you problems.
If you want to use ID as some sort of ranking then you have some options, referencing my answer here
The easiest way is to use the forloop.counter in a template or enumerate in a view:
# template
{% for object in objects %}
# rank is {{ forloop0.counter }}
{% endfor %}
# views
for index, value in enumerate(queryset):
# order is the index variable
...
If you want to explicitly add the rank to the queryset then you can use annotation:
from django.db.models import Window, F
from django.db.models.functions import DenseRank
queryset = Mix.objects.annotate(
ranking=Window(
expression=DenseRank(),
order_by=[
F('id').desc(),
]))
If you want to get Order Table data, you have to create an Order Serializer and link to this MixSerilizer, Like this,
class OrderSerializer(serializers.ModelSerializer):
class Meta:
model = Order
fields = ('id',)
class MixSerializer(serializers.ModelSerializer):
pub_date = serializers.DateTimeField(format="%m/%d/%Y,%I:%M:%S %p")
new_order = OrderSerializer()
class Meta:
model = Mix
fields = ('id','pub_date','detail','user','u_key','new_order')
models.py
class Mix(models.Model):
----
----
order = models.ForeignKey(Order, related_name=new_order, on_delete=models.CASCADE)
If want to get parent table data into a child table you have to pass "related_name" attribute in a models fields. and also that name in a child table sterilizer.

Django - How can i get this objects count based on this relationship

I have two models which are Influencer and InfluencerList. My model relationships are:
User and InfluencerList have many-to-one relationship (one user can have many lists)
Influencer and InfluencerList have many-to-many relationship (one influencer can be in multiple lists or one list can contain multiple influencers)
I want to display logged in users each lists name and count (how many influencers are in it)
I managed to list users own lists but i couldn't figured out how to get counts of that list. I suppose it should be done by using lookup (association) table.
Here is my model.py:
class Influencer(models.Model):
# fields are not included for clarity
def __str__(self):
return self.url
class InfluencerList(models.Model):
name = models.CharField('Name:', max_length=20, blank=False)
owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name='lists')
influencers = models.ManyToManyField('Influencer', related_name='lists')
def __str__(self):
return self.name
# some method like getCount() would be nice here
view.py:
class InfluencerListView(LoginRequiredMixin, ListView):
model = Influencer
context_object_name = 'Influencers'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
logged_in_user = self.request.user
context['InfluencerLists'] = logged_in_user.lists.all();
return context
I'm also not sure if i have to add a field like count to my InfluencerList model. It would be very nice if someone could explain why or why not i should do that. Thank you for your help.
logged_in_user.lists.values(
'name',
).annotate(
influencers_count=Count('influencers'),
)
It should return a list of dicts with:
[{'name': 'InfluenceList1', 'influencers_count': 10}, {'name': 'InfluenceList2', 'influencers_count': 20}]
Your particular Model structure and relationships it is possible that One User can have Multiple Lists of Influencers.
Because I am not sure what you want to achieve with the objects count I will just show you which are the methods able to access all counters...based on your sample code:
from django.db.models import Count
class InfluencerListView(LoginRequiredMixin, ListView):
model = Influencer
context_object_name = 'influencers' # recommended lowercase variables
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
logged_in_user = self.request.user
first_list = logged_in_user.lists.first()
first_list_influencers_count = first_list.influencers.count()
influencers_list = Influencer.objects.filter(lists__owner=logged_in_user)
influencers_count = Influencer.objects.filter(lists__owner=logged_in_user).count()
influencers_nested = logged_in_user.lists.values('name').annotate(influencers_count=Count('influencers'))
extra_context = {
'influencer_lists': logged_in_user.lists.all(),
'influencer_lists_counter': logged_in_user.lists.count(),
'first_list': first_list,
'first_list_influencers_count': first_list_influencers_count,
'influencers_list': all_influencers_list,
'influencers_count': all_influencers_count,
'influencers_nested': influencers_nested
}
context.update(extra_context)
return context
Note: If you only need the Counter/quantity it is better to use .count() if you also need the list then you can easily get the .all() | .filter() and get the counter from len(queryset_list) (.py files) OR {% queryset_list| length %} (html templates files).

Add properties to django models at runtime?

Specifically, I have django model objects I'd like to add properties to at runtime. It'd be great if this would work on any python class outside of Django.
I have the following models
models.py
class person(models.Model):
# ...
firstname=models.TextField(max_length=100)
lastname=models.TextField(max_length=100)
type=models.TextField(max_length=100)
address = models.ForeignKey(address, null=True)
class event(models.Model):
date=models.DateTimeField(auto_now=True )
name=models.CharField(max_length=100)
attendees = models.ManyToManyField(person)
def main():
p = person()
p.fisrtsname="Firsty"
p.lastname="Lasty"
p.addnewproperty(newtemporaryproperty)
p.newtemporaryproperty="This is a new temporary property"
when i use
person.newtemporaryproperty=property("")
I get a "Can't set attribute error" when trying to add a value to it.
I may be using it wrong.
EDIT
What i want to do is see if each person in a model has attended an event. and if they have, put a checkbox by their name. Here are the additional related files
tables.py
class AttendeesTable(tables.Table):
firstname = tables.Column()
lastname = tables.Column()
here = tables.TemplateColumn('<input id="attendee_{{ record.pk }}" {{
record.here }} type="checkbox" />',
verbose_name="Here?")
class Meta:
attrs = {'id': 'attendancetable', 'width': '100%', 'class': 'table
table-hover'}
template = 'django_tables2/bootstrap.html'
row_attrs = {
'id': lambda record: str(record.pk),
}
views.py
def markattendancepage(request):
person.here = ""
people= person.objects.all()
groups = group.objects.all()
eventid= 1 #set to 1 for testing
table=None
for p in people:
if event.objects.filter(id=eventid, attendees__pk=p.id).exists():
p.here = "checked"
else:
p.here = ""
table = app.tables.AttendeesTable(people)
RequestConfig(request, paginate=False).configure(table)
return render(request, 'app/user/attendancechecker.html', {'attendeetable':table})
pass
Because django model instances often get reloaded behind the scenes, you probably don't want to set attributes at runtime, because they can easily get lost. Instead, what you might want to do is have a property (or a method) in the class definition such as
class Person(models.Model):
first_name=models.CharField(max_length=100)
last_name=models.CharField(max_length=100)
#property
def is_in_category(self):
# 'calculation' return a boolean
return True if something else False
Then if you have any particular instance of Person you can check the is_in_category property
for person in Person.objects.all():
if person.is_in_category:
# do something
This also works in templates... for instance if you wanted to make a table of people
<table><tr><th>Name</th><th>In category?</th></tr>
{% for person in people %}
<tr>
<td>{{ person.first_name }}, {{person.last_name}}</td>
<td>{% if person.is_in_category %}Yes{% else %}No{% endif %}</td>
</tr>
{% endfor %}
</table>
However, because properties only exist as Python constructs, you cannot use SQL queries based on this property.
# this will not work
people_in_category = Person.objects.filter(is_in_category=False)
If you want to perform queries like this, you would need to create a field on the model or a related model or otherwise come up with an SQL expression that is the equivalent of the property.
Edit:
Given your models, you can perform a query that should do the same thing. Your event model has an attendees field which would be what you're looking for and would be the way to do this since it appears you have the event id in-hand and access to the event model.
evnt = event.objects.get(pk=eventid)
evnt.attendees # people who attended the event
did_not_attend = people.objects.exclude(id__in=evnt.attendees)
You may want to consider making a method on the model manager that annotates a query for the same effect that the property gives you. For example
class PersonManager(models.Manager):
def for_event(self, evnt):
attended_event = person.objects.filter(id__in=evnt.attendees)
qs = self.get_queryset()
return qs.annotate(attended=Exists(attended_event))
Then if you register this manager with your people model you can do
for p in person.objects.for_event(evnt):
if p.attended:
# they attended the event

How to display instances from two different django models on the same template, inside the same table?

In a django app I've created different models and everything looks okay until I try using data from two different models inside the same table.
To sum it up: in the homepage, I need to create a table that contains data from both the models, ordered by date.
The two models I need to display are the following.
models.py
class Document(models.Model):
number = models.CharField(max_length=10)
description = models.CharField(max_length=50)
assigned = models.BooleanField
validity_date = models.DateField
is_issued = models.BooleanField
class Program(models.Model):
name = models.CharField(max_length=25)
description = models.CharField(max_length=100)
validity_date = models.DateField
Then, I tried to create a view that would allow me to work with different models.
This is my view.py:
class BaseView(generic.ListView):
template_name = 'base/base_list.html'
context_object_name = 'base_list'
def get_queryset(self):
queryset = Document.objects.order_by('due_date')
return queryset
def get_context_data(self, **kwargs):
context = super(BaseView, self).get_context_data(**kwargs)
context['Programs'] = Program.objects.all()
context['Employees'] = Employee.objects.all()
return context
Now how can I create inside the template a table that shows both the models at once, ordering each entry by validity date (no matter if the entry belongs to Program or to Document)?
Thank you in advance!
You need to first query both the models, chain them together (Concatenate them) and then order by their shared attribute, that is the validity_date. You may do something like:
from itertools import chain
documents = Documents.objects.all()
programs = Program.objects.all()
final_combined_list = sorted(chain(documents,programs),key=lambda instance: instance.validity_date)
You can now simply pass final_combine_list to the template and render it to display it in the manner you want.
def get_context_data(self, **kwargs):
context = super(BaseView, self).get_context_data(**kwargs)
context['object_list'] = sorted(
itertools.chain(Document.objects.all(), Program.objects.all()),
key=lambda x: x.validity_date
)
return context

Categories