I'm writing after checking different threads on similar issues with no luck whatsoever, hence I'm sharing with you my problem hoping you can give me a hint on how to solve it.
I am trying to build a keyword ranking checker and I have two models, Keyword and Ranking:
models.py
class Keyword(models.Model):
keyword = models.CharField(max_length=100)
date_added = models.DateTimeField(default=timezone.now)
market = models.CharField(max_length=100)
domain = models.CharField(max_length=100)
class Ranking(models.Model):
keyword = models.ForeignKey(Keyword, on_delete=models.CASCADE)
position = models.IntegerField()
position_date = models.DateTimeField(default=timezone.now)
Basically, user will insert a list of keywords in the DB and an API will check each month the ranking for each keyword. The ranking model will store each ranking check and relate it to the keyword.
What I'd like to do is to display in the html template the list of keywords with their rankings (all of them because I want to show historical rankings too), and here is where I'm having issues. Basically I'm not able to retrieve all the rankings for a given keyword and pass it to the html as a template tag. I only can show the complete list of keywords and that's it.
views.py
def rankings(request):
keywords = Keyword.objects.filter(market="es")
return render(request, 'rankapi/marketview.html', {'keywords': keywords})
I've tried to do it the other way around, starting from rankings, but then I cannot display keywords which have no rankings.
views.py
def rankings(request):
ranking = Ranking.objects.all()
return render(request, 'rankapi/marketview.html', {ranking':ranking})
And then in the html:
marketview.html
{% for rank in ranking %}
{{rank.position}}{{rank.position_date}} {{rank.keyword.keyword}}
{% endfor %}
But this is not showing keywords with no ranking associated to them (recently added keywords or still not checked ones).
Do you have any hint to help me solve this issue?
Thanks a lot!
Not sure what do you mean by
Basically I'm not able to retrieve all the rankings for a given keyword and pass it to the html as a template tag. I only can show the complete list of keywords and that's it.
If there is a ranking object then its must that this ranking object have an associated keyword object because in your Ranking model, you make a ForeignKey relationship with keyword and its a required=True field, django expecting its a required field implicitly i.e you can not create a ranking object without a 'keyword'.
So if you able to retrieve any 'ranking' object , then you should get associated keyword like,
{% for rank in ranking %}
{{rank.position}}{{rank.position_date}} {{rank.keyword.keyword}}{{rank.keyword.domain}}
{% endfor %}
and so on..
I've found the solution which I post here for reference if someone has similar issues:
{% for keyword in keywords %}
{{keyword.keyword}}
{% for key in keyword.ranking_set.all %}
{{key.position}}
{% endfor %}
<br>
{% endfor %}
Rendering a page gets really slow when related objects are requested in a template.
class Item(models.Model):
name = models.CharField(max_length=160)
...
class Box(models.Model):
...
items = models.ForeignKey(Item, on_delete=models.CASCADE, null=True)
#template
{% for item in items %}
{{ item.box_set.first }}
{{ item.box_set.latest }}
{% endfor %}
Debug toolbar shows there many duplicate queries.
Why is this happening? Is there a way to speed this up?
The Django ORM has to make a request to the database when accessing a related field unless it's already cached. The main ways of caching the related objects are via select_related and prefetch_related.
What you're trying to do is a bit more difficult; you're trying to get two specific items from a collection. You can use .annotate() and Subquery to pull singular fields from a related model. This would be useful if you just wanted to display single field from box, but if you need the whole box instance this won't work.
First off, I want to say thank you to all of you here at stack-overflow. I have researched and been
able to find many of the answers to the questions I had on recursive relationships in Django; all
the way from Model creation, to views, to now the template. I am new to Python, therefore,
new to Django. So I thank you for the detailed examples in response to questions others have asked.
tl;dr
I needed to have a nested (ordered) list that has a foreign key relationship with another model. I tried using a recursive foreign key to "self" and was not able to accomplish the task with my research. Thanks to #somecallitblues (can someone tell me how to give him credit?)for pointing out Django-mptt, I was able to solve this problem.
(I don't know if or how to mark this question as answered and/or if I should change the title for others to be able to search if they have the same problem. I could use some help on formatting my question(s)/or the correct way to ask. Any pointers would be helpful.)
Models
from mptt.models import TreeForeignKey, MPTTModel
class Topic(models.Model):
wherein = models.CharField()
partof = models.CharField()
title = models.CharField()
slug = models.SlugField()
class TextNode(MPTTModel):
topic = models.ForeignKey(Topic)
parent = TreeForeignKey(
"self",
on_delete=models.CASCADE,
related_name="children",
related_query_name="child",
null=True,
blank=True,
)
body = models.TextField()
View
def topic_node_list(request, slug):
topics = Topic.objects.filter(slug__exact=slug)
textnodes = TextNode.objects.filter(topic__slug__exact=slug)
return render(request, "node_test.html", {"topics": topics, "textnodes": textnodes})
Template
{% load mptt_tags %}
<ul>
{% for topic in topics %}
<h2>{{ topic.title }}</h2>
<ul>
{% recursetree textnodes %}
<li>
{{ node.body}}
{% if not node.is_leaf_node %}
<ul class="children">
{{ children }}
</ul>
{% endif %}
</li>
{% endrecursetree %}
</ul>
{% endfor %}
</ul>
urls.py
urlpatterns = [
path("nodes/<slug:slug>/", views.topic_node_list, name="nodes"),
path("", views.home, name="home"),
path('admin/', admin.site.urls),
]
Everything works great! So thank you again #somecallitblues!
BUT! I would like to change to to an ordered list, and depending on the nested level, change the type. I would like the first ordered list to be 1.,2.,3 the next to be a., b., c., then i.,ii. iii. etc. Could the be done via JavaScript or jQuery? I do not even know where to look or what to search for in my search engine.
This is my first time doing a project in Python. I just started learning in December and I was tied of doing simple blogs and needed a challenge, and boy oh boy did I learn a lot! I am recovering from a major illness and have been out of commission for almost a decade, so getting back into the swing of things has been challenging. Python has helped me immensely for regaining muscle memory.
end tl;dr
I am trying to create a "report" (for lack of a better term) app. It has a table of contents, introductory,
however many sections you would like, bibliography, footnotes, index, glossary etc. I also have an app for
for questions that can be asked along with the ability to answer said questions, this is where I am having an
issue and the basis for my question. My code for Models, View and Template will be added below.
(if I can figure out how to post code).
I have a Subject model and a Body model. The Subject model is what the topic of the question is about.
The Body model is where the text of the questions are stored. Each question may or may not have a
sub-question. The Body model has a Foreign Key to the Subject model. The Body model has a recursive
Foreign Key to "self". This relationship is working fine, though I do have a "how do I" question
that I will list below. **
For the View I have a Generic ListView of the Subject model and added the extra context for the Body model.
The Template is the basis of my problem. I am able to nest ordered list of the "subject" and
the "body" of of the question being asked.
just fine. It's where I post the children of the questions (or sub-question).
The template will list the parent question in an ordered list along with it's children. Then the children
start listing as a parent question, so in essence they are posted twice. Once correctly as sub-question,
and then incorrectly as parent question (though I would like to know how to list a sub-question as the
parent to a sub-question (a grandchild relationship?).)
I have thought of doing both a custom model manager or class method(s) to sort out the parents from
the children, but how would I go about doing that? As I said, I am new to python and Django, so I haven't
a clue.
I am using:
Django version: 2.1.8
Django-pyodbc-azure 2.1
python 3.7.2
Here is my code:
Models
class Subject(models.Model):
...
wherein = models.CharField(
max_length=3,
choices=WHERE,
default=SECTION,
help_text="Where in the report",
)
partof = models.CharField(
max_length=5,
choices=PART_OF,
default=QUESTION,
help_text="Is this a question or answer?")
title = models.CharField(
max_length=80,
help_text="What is the subject of the question",
)
slug = models.SlugField(
max_length=80,
help_text="This is what the url will be"
)
class Body(models.Model):
subject = models.ForeignKey(
Subject,
on_delete=models.CASCADE,
verbose_name="subject of",
help_text="What subject does this text relate to?"
)
parent = models.ForeignKey(
"self",
on_delete=models.CASCADE,
verbose_name="subsection of",
related_name="subsections",
related_query_name="subsection",
null=True,
blank=True,
)
text = models.TextField(
max_length=1500,
help_text="Text of the paragraph",)
View
class QuestionList(ListView):
queryset = Subject.objects.filter(id=2)
template_name = "questions/questions_list.html"
context_object_name = "subjects"
def get_context_data(self, *args, object_list=None, **kwargs):
context = super(QuestionDetail, self).get_context_data(**kwargs)
context["bodies"] = Body.objects.filter(subject__partof__exact="QUES")
return context
Template
<ol type="1">
{% for subject in subjects %}
<li><b>{{ subject.title }}</b></li>
<ol type="a">
{% for body in bodies %} # I believe this is where I need to filter for just parents
<li>{{ body.text }}</li>
<ol type="i">
{% for sub in body.subsections.all %}
<li>{{ sub.text }}</li>
{% endfor %}
</ol>
{% endfor %}
</ol>
</ol>
{% endfor %}
I would like to have an option to nest further (have children of the child of the parent).
Should I add extra context for parents:
Body.objects.filter(parent_id__isnull=True)?
if so, how, in the templates, would that work with the relationship w/the children? (nesting the list).
** a side question: How would I make "child" a parent to their own "child"?
and how would those be nested in the template?
I hope I have laid out my issue properly, I tried to post as much as I could and I am hoping it's an easy
way to solve. If there is anything that I have missed, please feel free to ask!
Thank you!
UPDATE:
Here is what the template to render as html
# The first ol
<li>1. This would be the topic a question</li>
<li>a. This would be the parent question.</li>
<li>i. This would be the child of the parent question a.</li>
<li> ii. This would also be a child of the parent question a.</li>
<li>b. This would be the second parent question</li>
<li>c. This would be the third parent question</li>
<li>i. This would be the child of the parent question c.</li>
<li> ii. This would also be a child of the parent question c.</li>
<li>d. … and so on</li>
<li>2. This would be the next topic of a question</li>
UPDATE 2:
I realized I didn't update how things are rendering now. Here it is:
<li>1. This would be the topic a question</li>
<li>a. This would be the parent question.</li>
<li>i. This would be the child of the parent question a.</li>
<li> ii. This would also be a child of the parent question a.</li>
<li>b. This would be the second parent question</li>
<li>c. This would be the third parent question</li>
<li>i. This would be the child of the parent question c.</li>
<li> ii. This would also be a child of the parent question c.</li>
<li>d. … and so on</li>
<li>e. This would be the child of the parent question a.</li>
<li>f. This would also be a child of the parent question a.</li>
<li>g. This would be the child of the parent question c.</li>
<li>h. This would also be a child of the parent question c.</li>
<li>i. … and so on</li>
<li>2. This would be the next topic of a question</li>
I am current reading Django docs about adding a custom model manager. A bit confused, but I will persevere on trying new ways of doing things. Like I said, I am a bit lost at this point in time and could really use some help.
UPDATE 3
I took the advice of #somecallitblues and took the time to go through both Django-treebead and Django-mptt. With Treebeard I couldn't figure out how to work with templates. With mppt I was able to build the models, but unable to connect the two models together for displaying in the template, and the view I had to hard-code a topic_id. I feel like I am missing something. Can anybody point me to where my problems are? I am reading all the documentations, but not understanding where and how to apply the methods. I am very new to web development along w/being a newbie to python.
I will post what I have right now, and if someone can give me some pointers on what I should be looking into, I would be grateful.
For the models, Subject is still the same, except it's named Topic, so I won't repost that:
updated body model:
class BodyNode(MPTTModel):
topic = models.ForeignKey(
Topic,
on_delete=models.CASCADE,
verbose_name="Of topic",
help_text="What topic is being discussed?",
)
text = models.TextField(
max_length=750,
help_text="Content of the paragraph",
)
parent = TreeForeignKey(
"self",
on_delete=models.CASCADE,
related_name="children",
blank=True,
null=True,
)
View:
def topic_list(request):
bodynodes = BodyNode.objects.filter(topic_id=2)
return render(request, "mpttapp/topic_list.html", {"bodynodes": bodynodes})
Template:
<ol class="root" type="a">
{% recursetree bodynodes %}
<li>
{{ node.text }}
{% if not node.is_leaf_node %}
<ol type="i" class="children">
{{ children }}
</ol>
{% endif %}
</li>
{% endrecursetree %}
</ol>
Right now, the list displays as it should, but only for topid_id=2.I need that to be dynamic, along with being able to add the slug field for the url,along with being able to use the title field from the Topic model, so I am half way there.
I do want to thank #somecallitblues for helping me, I feel that using mptt is the way to go as I'll be able to do deeper nesting if need be. I just feel like I am a bit over my head, but I am really determined to figure this out. I just need some pointers.
UPDATE 4
I think I have figured out the relationship problem. I am going to make the Topic Model into an MPTTModel w/a TreeForeignKey from the BodyNode. I think the relationship to the Topic model is the nesting issue I am having. Since the app itself is "sort of" a tree/directory object to begin with, that could be the reasons for my struggles. I'll update again tomorrow if this works, I would really like to solve this and have this topic be helpful for anyone else who comes along w/the same issue.
I do spend A LOT of time reading the documentation on Django-project site, yet I am still a bit confused on building the templates/views. If anyone knows a good tutorial site or a good book that does more than build a simple blog, I would be grateful for the recommendation.
I am trying to create a Django app where a user (say a researcher or a teacher) can create content for other users (participants or students) where any given page may include any number of content items (such as surveys questions, text, and/or images), and these items can be arranged by the teacher in any order on a page.
I'm taking an approach similar to the last chapters (10-12) of the book Django by Example. The app from those chapters comes very close to giving an example of my case using an e-Learning platform app, but they only allow teachers to create Content like Text and Images, they do not allow teachers to create survey questions for students. Here is the general approach that I am following.
The book models content for text and images for a given page like so:
class Content(models.Model):
page = models.ForeignKey(Page, related_name='contents')
content_type = models.ForeignKey(ContentType,
limit_choices_to={'model__in':('text',
'image')})
object_id = models.PositiveIntegerField()
item = GenericForeignKey('content_type', 'object_id')
order = OrderField(blank=True, for_fields=['page'])
class Meta:
ordering = ['order']
class ItemBase(models.Model):
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
def render(self):
return render_to_string('courses/content/{}.html'.format(
self._meta.model_name), {'item': self})
class Text(ItemBase):
content = models.TextField()
class Image(ItemBase):
file = models.FileField(upload_to='images')
There's an interface for teachers to fill out and order this content for a page.
Content is rendered within a template like so:
<div class="page">
{% for content in page.contents.all %}
{% with item=content.item %}
<h2>{{ item.title }}</h2>
{{ item.render }}
{% endwith %}
{% endfor %}
</div>
And the html used in the render method for a Text Content is simply:
{{item.content|linebreaks|safe }}
I don't find it difficult to extend this with QuestionTypes that extend ItemBase (similar to Text and Image models), as well as creating a StudentAnswer model for storing answers in the database.
I would probably override ItemBase render and put it into the QuestionType model so that I could pass a StudentAnswer model form into the context for the QuestionType html file.
I could then just have the html that is rendered contain {{ form }} for simplicity sake, and we now have a question that acts like any other content item and can be ordered with all of the others. This assumes that the HTML that contains the content has a form tag that encompass all of the rendered content items.
My problem is handling the POST request in the view. I have no idea how to validate and save answers from multiple forms on any given single page generated in this way. Examples I find assume a consistent number of forms that you know by name and are of different types.
I've also played around with the idea of creating a single dynamically generated form, but the examples I've seen for that assume you will loop through the fields in the template and display them in order rather than my requirement that a teacher determines the order which may include text or images in-between questions.
Is there a way to create what I'm looking for or can someone point me in the right direction?
I have 2 models called Valuation and Assessment. A valuation has many assessments (foreignkey relationship). Users can only create 1 assessment for each valuation.
This seems to be very simple but I can't wrap my head around it. I need to check if any of a valuation's existing assessments belongs to the request.user, how do I do that?
this doesn't work because assessment_set.all is a list. (assessments in this case is a list of assessments for the currently displayed valuation)
{% if request.user.assessment_set.all not in assessments %}
# Display "make an assessment" form
{% endif %}
So I think I'd need to loop over request.user.assessment_set.all and see if each of the user's assessments is in the assessments list, but I feel like that is very inefficient and there must be a better way. Advice?
Based on your description I assume you have the following model architecture(i have used related_name for the reverse relationships),
class Valuation(models.Model):
# fields
class Assessment(models.Model):
#fields
user = models.ManyToManyField(User, related_name='assessments')
valuation = models.ForeignKey(Valuation, related_name='assessments')
So if you want to limit the logged in user to create only 1 assessment for each valuation, then you present only those valuations that are not assessed.
views.py
unassessed_valuations = Valuation.objects.exclude(assessments__user=request.user)
template
{% for valuation in unassessed_valuations %}
valuation assessment form
{% endfor %}