Hi i'm sure this had a simple solution but i cant find it! It must be required ALL the time!
To learn django i am writing simple app for me to log my learning points. So i have two models:
class Topic(models.Model):
title = models.CharField(max_length=40)
def __unicode__(self):
return self.title
class Meta():
ordering = ['title']
class Fact(models.Model):
note = models.CharField(max_length=255)
topic = models.ForeignKey('Topic')
def __unicode__(self):
return self.note
class Meta():
ordering = ['note']
I have template and url that will list ALL the topics.
When i see that list i want to be able to click on it [which i can do] and have that topic and all the facts linked to it (thourgh the foreign key appear) [would that technicaly be described as filtered query set of child objects?] I am using detailview.
url
url(r'^(?P<pk>\d+)/$', TopicDetailView.as_view(), name='facts'),
Here is the code of the detail view. Know i knows it knows the pk as it shows the right page when i take out the extracontext filter (and just take .all()). But i cant ref it no matter how many ways i try. I'd like something like this...
class TopicDetailView(DetailView):
model = Topic
template_name = 'study/topic_facts.html'
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super(TopicDetailView, self).get_context_data(**kwargs)
# Add in a QuerySet of all the books
context['fact_list'] = Fact.objects.filter(topic='pk')
return context
I can do this if i put some logic and a filter in the template but that doesn't seem very proper to me and i feel i must be able to do this easily by adding the right extra context.
Help some poor newbie out! Many Thanks.
'pk' is just a string. You mean self.kwargs['pk'].
But actually you don't want to do this at all. The super class already adds the Topic object to the context: and you have a relationship between Topic and Fact. You can traverse this relationship in the template:
{% for fact in topic.fact_set.all %}
...
{% endfor %}
so you don't need to override get_context_data.
Related
I have two models, field of one of them pointing to the other as shown below:
class Group(models.Model):
group_company_id = models.CharField(primary_key=True, ...)
class Company(models.Model):
company_id = models.CharField(primary_key=True, ...)
group_company = models.ForeignKey(Group, related_name="related_grp_company", ...)
I am trying to get all the Companies that have been created for a particular Group. So I am trying to get the company_id (and other) values in Djnago UpdateView as a list in the template. My CBV is as shown:
class GroupCompanyChangeView(UpdateView):
template_name = ...
model = Group
form_class = ...
success_url = reverse_lazy('group_list')
grp_coy_units = Group.objects.prefetch_related('related_grp_company') # I am trying to get the values of `company_id` in the template but nothing is displayed.
Could somebody please let me know how to get this to work?
Update
As explained (#Mahmoud Adel), I have modified my UpdateView as shown below:
class GroupCompanyChangeView(UpdateView):
template_name = ...
model = Group
form_class = ...
success_url = reverse_lazy('group_list')
def get_object(self, *args, **kwargs):
return Group.objects.get(pk=self.kwargs['pk'])
And then in the template, I am doing:
{{ group.related_grp_company }}
With this I am getting an output of <app>.Company.None.
UPDATE: After testing on my local env to solve the problems reported in the comments, this is the final answer
You should override get_object()
def get_object(self, *args, **kwargs):
try:
return Group.objects.prefetch_related('related_grp_company').get(pk=self.kwargs['pk'])
except:
return None
Note that order matter here in the above query, doing prefetch_related before get fixes the error for 'Group' object has no attribute 'prefetch_related'.
Also, you can drop using prefetch_related and only do get from the above query and it will work too, but using prefetch_related is suggested to optimize performance as you will fetch the related companies every time
Then at your template you can simply call related_grp_company.all from the object, let's say that you are passing the current Group object as group to your template, so it should like group.related_grp_company.all, this is a QuerySet list, so loop over it or do whatever you want.
for ex:
{%for d in object.related_grp_company.all%}
<h1>{{ d.company_id }}</h1>
{% endfor %}
Because we didn't add all we were getting<app>.Company.None earlier
Tip:
related_name is used for the reverse relation, I would suggest renaming it to companies so it would be more clearer, for ex:
group_company = models.ForeignKey(Group, related_name="companies", ...)
so using it later will be like group.companies()
For example, the voting feature for a stackoverflow question.
if user has voted:
highlight arrow
if the model is set up like so:
class Question(models.Model):
#....
voters = models.ManyToManyField(User)
Is it best to do something like
views.py
class DisplayQuestion:
def __init__(self, question, user):
self.__dict__ = question.__dict__.copy()
self.has_voted = user in question.voters.all()
def show_question(request, question_pk):
question = Question.objects.get(pk=question_pk)
render('question.html', {'question':DisplayQuestion(question, request.user)})
or pass it as another variable?
def show_question(request, question_pk):
question = Question.objects.get(pk=question_pk)
render('question.html', {'question':question,
'has_voted':user in question.voters.all()})
This seems less ideal. You might want to display a whole bunch of questions, and not pass a has_voted for each one.
or is the best way to check via an ajax() call?
The simplest way is to just annotate an attribute before sending to the template.
question.has_voted = user in question.voters.all()
I have a database containing books. On mysite.com/books, this database is presented in table form, with the title and the author displayed as columns and books are rows.
When a user clicks on a book title, it leads to a details page: mysite.com/books/slug-of-specific-book. I have managed to get this working fine, but I'm having trouble figuring out how to access the information of the specific book on the details page. Namely, I'm uncertain if I'm configuring my view for this correctly. I'd like to be able to access something like {{ book.name }} in the template page for the details page and have that display at the top, for instance.
models.py
class Book(models.Model):
name = models.CharField(max_length=200)
author = models.CharField(max_length=200)
slug = models.SlugField(unique=True)
def get_absolute_url(self):
return reverse("Details", kwargs={"slug": self.slug})
urls.py
url(r'^books/(?P<slug>[-\w]+)/$', inventory.ShowDetails.as_view(), name="Details"),
views.py
class ShowDetailedListing(ListView):
template_name = "detailed_book.html"
def get(self, request, *args, **kwargs):
return render(request, self.template_name)
Could someone please give me some pointers on how to write this view so that I can access something like {{ book.name }} in "detailed_book.html"? I tried seearching online for this (as it seems really simple), but couldn't quite find anything, probably because I'm not sure how to phrase this.
DetailView might be more appropriate than list view since it seems you want to display information on 1 object
you can set the context_object_name to book
Using detail view should automatically map the slug field in your url to the slug on your Book model
class BookDetailView(DetailView):
model = Book
context_object_name = 'book'
Following on from this question...
I have two primary models for my blog, Article and Link, and both are subclasses of Post. Simplifying a little, they look something like this:
class Post(models.Model):
title = models.CharField(max_length=100)
body = models.TextField()
post_date = models.DateField(db_index=True, auto_now_add=True)
class Article(Post):
feature_image = models.FileField(upload_to='feature_images')
class Link(Post):
link = models.URLField(verify_exists=True)
I want to collect over both Articles and Links, so in my view, I run Post.objects.order_by('post_date') and presto, I get the whole list--but only with the fields that are on Post. If I want to use the link in a Link instance, I can't.
I have the primary key, so I should be able to do something like Link.objects.get(pk=item.pk) and be set--but I'd have to know if this was a Link or an Article.
Can I create a post_type property on the parent model and write to it with the correct model name from the children?
I solved this in a totally different way in the end, by writing a custom manager for Post:
class PostManager(models.Manager):
def __get_final(self, pk):
for k in Post.__subclasses__():
if k.objects.filter(pk=pk).exists():
return k.objects.get(pk=pk)
return None
def __subclass_queryset(self, qs):
collection = []
for item in qs:
collection.append(self.__get_final(item.pk))
return collection
def all(self):
return self.__subclass_queryset(super(PostManager, self).all())
Now Post.objects.all() (or any other QuerySet operation I add to the manager, like order_by), and I'll get back a list of all of the objects, with their full set of specific fields. (I then reset the manager on the subclasses, so they're not saddled with these extra queries for routine operations.)
I know this is a very basic concept in Django, and I have tried the tutorial but it is not working. I am working on a comic book database with the models set like this (at least, a sample of two of the models):
Class Title(models.Model):
title = models.CharField(max_length=256)
vol = models.IntegerField("Vol.")
slug = models.SlugField(blank=True, null=True)
#desc = models.CharField(max_length=256)
class Meta:
ordering = ['title']
def get_absolute_url(self):
return "/comics2/title/%s" % self.slug
def __unicode__(self):
return self.title
class Issue(models.Model):
title = models.ForeignKey(Title)
number = models.IntegerField(help_text="Enter the number only. Do not include the hashtag.")
writer = models.ManyToManyField(Creator)
What I am trying to do is create a page that shows a list of all the issues within that Title.
But, I have it setup in the views like this:
class AstonishingXMenIssueListView(ListView):
context_object_name = "astonishing_list"
queryset = Issue.objects.filter(title__title="Astonishing X-Men").order_by("number")
template_name = "comics2/astonishing_list.html"
My urls.py look like this:
(r'^comics2/title/(?P<title_slug>[-\w]+)/$', AstonishingXMenIssueListView.as_view(
)),
Of course, going to /uncanny-xmen-v1/ shows the same thing as the Astonishing link above.
Obviously, this is not a practical way to list issues by title for future issues and titles, so I need it setup so that I don't have to individually do this. Now, I have tried following the Django generic views tutorial, but I got an index tuple error.
I've tried this, but it doesn't work. This is what gets me the index tuple error.
class IssuesByTitleView(ListView):
context_object_name = "issues_by_title_list"
template_name = "comics2/issues_by_title.html",
def get_queryset(self):
title = get_object_or_404(Title, title__iexact=self.args[0])
return Issue.objects.filter(title=title)
Any ideas? And can someone please reply in baby-language, as I am new to Django and Python, so simply telling me to look at the Tutorial again isn't going to help. So, maybe writing out the code would help! Thanks!
Generally, your IssueByTitleView is the right way to do it. But as you use named groups in your URL regex (the (?P<title_slug>[-\w]+) part of your URL), you have to access the URL parameters through self.kwargs instead of self.args. Also, you have to filter on the slug field, not the title field:
title = get_object_or_404(Title, slug=self.kwargs['title_slug'])