obj.authors.all() doesn't show anything - python

I'm trying to make a django site in the latest version of django, but when i use the obj.authors.all() it returns nothing.
I have tried getting rid of the all() but returns empty Queryset.
views.py
def menu(request):
obj = Book.objects.get(id=1)
obj = obj.authors.all()
else:
obj=""
return render(request, 'menu.html',
{'obj':obj,'numautgors':authors})
models.py
class Book(models.Model):
name = models.CharField(max_length=100,unique=True)
authors = models.ManyToManyField(User)
text = models.TextField(unique=True)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('model-detail-view', args=[str(self.id)])
I expect it to return the authors, but it returns nothing.
Sorry if a duplicate. And one more question can i show all book written by a specific author or in this case User?

You can try :
Books.objects.all().values('authors')
And suppose you want to show a book written by specific author then in that case your query should be :
Books.objects.filter(authors__username=request.user.username)
also you can use get based on your scenario
Taking assumption that your User model has username field.

I think you are sending the wrong context, so try like this:
def menu(request):
obj = Book.objects.get(id=1)
authors = obj.authors.all()
return render(request, 'menu.html', {'obj':obj,'numautgors':authors})
Alternatively you can show the authors in template directly(you don't need to pass authors to template with context at all):
{% for author in obj.authors.all %}
{{ author.id }}
{% endfor %}

You are overwriting your variables
Firstly with
obj = Book.objects.get(id=1)
You are assigning the Book object retrieven from the database to the obj variable.
Then with
obj = obj.authors.all()
You assign authors to obj again, and then you are returning authors, a variable that does not exist.
Your naming seems confusing.
If you want the authors of the book with id 1, you could do this:
authors = Book.objects.filter(id=1).authors.all()

Related

Injecting custom data into Django Queryset before passing to template

What is the best way to append or inject some extra data into a Django QuerySet?
Imagine a situation where I am displaying a list of Books, and I want to show the result of a special calculation on each one:
models.py
class Book(models.Model):
name = models.CharField(max_length=64)
book_list.html
{% for book in objects %}
{{ book.name }} - {{ book.special_result }}
{% endfor %}
views.py
class BookListView(ListView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
books = self.object_list
for book in books:
book.special_result = do_special_calculation(foo=bar)
context['books'] = books
return context
Imagine that do_special_calculation() method cannot be calculated in the template or as a model parameter, because it needs to have a variable foo passed in.
This code does not achieve the desired result of making each book's special_result value accessible from the template, because the book variable is overwritten with each iteration of the for loop. Every solution I've come up involves basically building out a new dictionary in parallel with the QuerySet, passing that into the template, and looping through them both in the template simultaneously, causing very ugly code.
I also don't want to save the result of do_special_calculations() back to the database for a host of reasons (efficiency, potential stale data, can't easily save an object).
What would be the best approach to make each entry's special calculation available in the template?
I finally solved this by making an empty list and using setattr() on each entry. Here is a fixed code example:
class BookListView(ListView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
books = self.object_list
book_list = []
for book in books:
special_result = do_special_calculation(foo=bar)
setattr(book, "special_result", special_result)
book_list.append(book)
context['books'] = book_list
return context

cannot retrieve values from database django

I have a table I am trying to retrieve values from. It has two foreign keys and that is it.
I use get_or_create on the table and create an object. I verify with the admin panel that the object is there. Then, I try to retrieve it but I do not get the values even though I can see them in the admin panel.
Here is the table:
class req(models.Model):
to = models.ForeignKey(User,on_delete=models.CASCADE)
from = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return "request sent"
In the piece of code below, I am retrieving from the database and I try to display it as it is in the p tag(html). In the template, I tried {{ req.to }} and {{ req.from.first_name }} but in vain, I did not see any values when html is rendered.
def get(self, request):
u = get_user(request)
try:
my_requests = req.objects.get(from=u)
except req.DoesNotExist:
fr = None
if fr == None:
return redirect(reverse('myapp:index'))
if my_requests != False:
context_dict['req'] = my_requests
return render(request, 'myapp/req.html', context=context_dict)
Can anybody see the problem that I cannot and comment ?
There are couple of issues in your code. here is the updated version which address your issue :-
def get(self, request):
req_obj, created = req.objects.get_or_create(from=request.user)
if created:
context_dict['req'] = my_requests
return render(request, 'myapp/req.html', context=context_dict)
return redirect(reverse('myapp:index'))

Sorting queryset results in a template

I have the following model:
class TestCase(models.Model):
tc_id = models.CharField(max_length=20)
tc_title = models.CharField(max_length=500)
class TestSteps(models.Model):
ts_case = models.ForeignKey(TestCase, on_delete=models.CASCADE)
ts_seq_no = models.IntegerField(default=1)
ts_instruction = models.CharField(max_length=200)
I want to display a test case together with its associated test steps in the template. For this I have written two views, one is not so nice but works:
def tc_steps(request, pk):
case = TestCase.objects.filter(id=pk)
steps = TestSteps.objects.filter(ts_case_id=pk).order_by('ts_seq_no')
context = {'case': case, 'steps': steps}
return render(request, 'testman/tc_steps.html', context)
Not very nice because I have to retrieve two querysets. Better to have this one:
def tc_steps(request, pk):
case = TestCase.objects.filter(id=pk)
return render(request, 'testman/tc_steps.html', {'case': case})
because this contains all the information I need in the template. Now the problem:
In the template for the second view I use the following tag to display the test steps:
{% for step in case.first.teststeps_set.all %}
Which works but the steps aren't in the right order. In the template for the first view I just use:
{% for step in steps %}
And get the correct order (sorted by ts_seq_no) because I did the sorting in the view already. I tried to use a filter but couldn't find one that does what I want. My question is, is there any way to do an order_by in the template tag?
You can use dictsort like this(use dictsortreversed for reversed order):
{% for step in case.first.teststeps_set.all|dictsort:"ts_seq_no" %}
I would add a method to the TestCase model to return its related steps in the required order.
class TestCase(models.Model):
...
def ordered_steps(self):
return self.teststeps_set.order_by('ts_seq_no')
Now in the template you can do {% for step in case.first.ordered_steps %}.

Django Haystack: How to index field from another class

I have a django model Story which I am successfully able to index using templates. However there is another model Reviews which has a static method which takes Story object and returns ratings as Integer. How can I index Story on ratings also.
{{ object.story_name }}
{{Reviews.ratings(object)}}
I tried to call this method in template story_text.txt, but that results in an error.
django.template.exceptions.TemplateSyntaxError: Could not parse the remainder: '(object)'....
Edit:
I tried using below in template, it doesn't give any error while building the index. But how can I now refer to this field while searching using SearchQuerySet
Reviews.average_start_rating( {{object}} )
I am confused. I don't think that you can use syntax like {{ Reviews.rating object }} with template engine in Django. If it is possible, that is what I didn't know.
Why don't you pass what you want to show in template in Context in the first place?
{{ object }} could be rendered because it has object in Context. For example, if you use UpdateView(class based view), It contains object in Context automatically.
class Example(UpdateView):
model = yourClass
form_class = yourFormClass
template_name = yourhtml
success_url = URL redirect page after success
you can use {{object}} in yourhtml.html because of UpdateView. you give pk number in url conf like (?P<pk>[0-9]+).
you can do like this without UpdateView
class anotherExample(View):
def get(self, request, *args, **kwargs):
render(request, 'yourhtml.html', {"object": Class.objects.get(id=self.kwargs['pk'])})
in form view, you can use
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['object'] = Class.objects.get(id= ... )
return context
my idea is passing story object and review object which has FK of story object together in context.
I was able to get it working using haystack advanced-data-preparation.
Advanced Data Preparation
Using an additional field one can have a prepare method for that. However only issue is I can order the data using this field but can't search using it.
class StoryIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True)
ratings = indexes.FloatField()
def prepare_ratings(self, obj):
return Reviews.ratings(obj)
def get_model(self):
return Story
Instead of using a template for the text field, here you can use the prepare or prepare_FOO methods:
class StoryIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True)
# text = indexes.CharField(document=True, use_template=True)
# ratings = indexes.FloatField()
def prepare_text(self, obj):
return "\n".join(f"{col}" for col in [obj.story_name, Reviews.ratings(obj)])
def get_model(self):
return Story

Queryset object has no attribute 'Name'

I am working on my first django project and i am having problems displayin 'categories' from my database onto a webpage as a list. I am getting the error "object has no attribute 'Name'. My code so far is:
Model:
class Category(models.model):
name = models.Charfield(max_length=128)
def __unicode__(self):
return self.Name + ": " +str(self.id)
Views:
from django.shortcuts import render_to_response, redirect
from forms.models import Form, Group, Flow, Gate, Field, Event, Category
from django.core.context_processors import csrf
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse
def homepage (request):
CatName = Category.objects.order_by('id')
output = {
'category_name': CatName.Name,
}
return render_to_response('forms/formsummary.html', output)
HTML:
<div>{{ category_name }}</div>
Can anybody point me in the right direction?
In Django, when you use the ORM to query for objects, there are two possibilities (excluding each case returning nothing):
Query returns just one objects: if so, you queried using the get() method of the manager.
Query returns a collection: if so, you queried by using an all(), filter() or any method like those.
In this case, your query returned a collection of Category objects, you can do a couple of things about this, you can either generate a list with only the names by using a list comprehension:
cnames = [c.name for c in Category.objects.all()]
Or you can iterate the list using a for loop and do whatever you need to do with each object.
Django already orders your data by the id field, so, I guess there is no need to specify an ordering in this case.
Later, when your view is returning, you can deliver the list to your template and iterate it to extract what you need, for example.
In your view:
def get_categories(request):
categories = Category.objects.all()
context = {'categories': categories}
return render_to_response('template.html', RequestContext(request, context))
Then, in your template:
{% for c in categories %}
<p>{{c.name}}</p>
{% endfor %}
Here's some useful documentation
Django Templates
Django Querysets
Hope this helps.
It seems like case sensitive,
def__unicode__(self):
return self.Name + ": " +str(self.id)
^
name
CatName is a collection of Category instances. The CatName object does not have a name property because it is not a Category object. It contains Category objects.
you can iterate through your collection and display each categories name:
for category in CatName:
print category.name
It is good to at least read through QuerySet documentation even if you don't fully grasp it yet.
if you want just the most recent category you could do something like:
def homepage (request):
most_recent_category = Category.objects.order_by('-id')[0]
output = {
'category_name': most_recent_category.name
}
return render_to_response('forms/formsummary.html', output)

Categories

Resources