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)
Related
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()
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 %}.
I have a view that allows me to work with two different models at once, thanks to itertools chain. I'm rendering the instances of the two chained models inside a table in my template, and I'd need the rows of the table to be formatted differently in case the instances are from one model as opposed to the other.
So basically: I'm chaining two models and displaying their instances in a table, and all the rows of the table that contain instances from model A should be formatted with a yellow background and all the rows containing instances from model B should have a blue background instead.
This is the view:
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['object_list'] = sorted(
itertools.chain(Program.objects.all(), Document.objects.all()),
key=attrgetter('validity_date'),
reverse=True)
return context
In logic, what I'd need in the template would be something like this:
if
object in object_list ***belongs*** to Program.objects.all()
(etc)
else
(etc)
The question is: how should I express that belongs?
I've also looked into template tags but could not find the right way to go.
Thank you in advance.
As I mentioned in the comments, you should look for a way of identifying the model itself rather than checking if it is in a list. There is a built-in way of accessing the model name, but unfortunately that is inside the _meta attribute and you're not allowed to use attributes that start with underscores in a template.
So instead I would recommend simply adding one to your class definitions:
class Program(models.Model):
model_name = 'Program'
...
Now you can just do:
{% if object.model_name == 'Program' %}
...
{% else %}
...
{% endif %}
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
So I have a model Listing() that has a field views. In my one of my views, when someone looks at the listing's page, the views field is incremented by one via listing.views = F('views') + 1 and listing.save(update_fields=['views']). My issue is that when I access the views attribute from that same template using {{ listing.views }}, instead of display the current amount of views, the template displays F(views) + Value(1) (literally that text). Now, I assume I could use a Model method such as def get_views() which will return self.views, but I was wondering why I am getting this weird issue. Also, is there a way without writing a model method that I can get the actual integer instead of the odd F(views) + Value(1)?
Here is my current code:
models.py
class Listing(models.Model):
...
views = models.IntegerField(default=0)
listings.py
class ListingView(View):
def get(self, request):
listing_id = request.GET['listing_id']
listing = get_object_or_404(Listing, id=listing_id)
listing.views = F('views') + 1
listing.save(update_fields=['views'])
return render(request, 'listings.html', {'listing': listing})
listings.html
<html>
{{ listing.views }}
</html>
Using F expressions like this requires you to re-fetch the item once saved in order to get updated values (due to the nature of the F expression updating at a database level and not the model instance itself; perhaps that's where the decrease in operational costs come in).
From the docs -
In order to access the new value that has been saved in this way, the object will need to be reloaded:
reporter = Reporters.objects.get(pk=reporter.pk)
# Or, more succinctly:
reporter.refresh_from_db()