How should I add category in template? - python

Models:
class Category(models.Model):
name = models.CharField(max_length=20)
slug = models.SlugField(max_length=200, unique=True )
def __unicode__(self):
return self.name
class Post(models.Model):
title = models.CharField(max_length = 100)
content = models.TextField(max_length = 600, default = 'cool' )
date_of_creating = models.DateTimeField(auto_now=False, auto_now_add=True)
image = models.ImageField(
upload_to=upload_location,
null=True,
blank=True,
height_field="height_field",
width_field="width_field"
)
height_field = models.IntegerField(default=0)
width_field = models.IntegerField(default=0)
category = models.ForeignKey('Category')
slug = models.SlugField(unique=True, blank=False)
def __unicode__(self):
return self.title
Views:
def category(reguest, slug):
category = Category.objects.get(slug=slug)
post = Post.objects.filter(category=category)
html = 'category.html'
context = {
'category': category,
'post': post,
}
return render(reguest, html, context)
def listofposts(request):
query_set_list = Post.objects.all()
context = {
"list" : query_set_list,
}
html = 'base.html'
return render(request, html, context)
I dont know what should I write in template to filter my posts by categories.
I need to choose category and display posts of this category. How can I filter it by category?

I believe you are asking how to show your posts, arranged by categories? If that is what you are after, your template should look something like this:
template.html
{% if category %}
{% if post %}
{% for c in category %}
{% for p in post %}
{% if p.category == c %}
<div>{{ p.title }}</div> <!-- and whatever else you want to display and however you want to style it I am just giving an example -->
{% endif %}
{% endfor %}
{% endfor %}
{% endif %}
{% endif %}
Based on what you do in your views, this is one way to display by category. Note there are better ways of how you can traverse the data, and group them up, but you are asking for this. So I hope this helps you out!
EDIT 1
After reading your question again (i believe there was an edit) I saw that you are asking how to show the posts for the selected category. I am assuming that since you have a slug the category selected is in the URL. So indeed in the view you are selecting the correct posts. So in order to display the posts from the selected category you simply have to do this in your template:
{% if post %}
{% for p in post %}
<div>{{ p.title }}</div> <!-- and whatever else you want to display and however you want to style it I am just giving an example -->
{% endfor %}
{% endif %}
Hope this helps!

You can try to use Ajax to filter by category (Tutorial here).
Make a selection box containing all the categories, then when a new option is selected, trigger the Ajax query to select all posts from that category.

Related

Django filter queryset in template

I'm still studying in school and still new in Python language & Django framework and I'm trying doing projects to learn the best practice for it.
Right now I'm building a project like following :
Topics Model => which is user can write a new topic
Replies Model => which is user can write a new reply for a specific topic
Likes Model => which is user can vote up or down for a topic or reply
it's a little bit close from stackoverflow site .
Models.py
class Topic(models.Model):
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
title = models.CharField(max_length=400)
like = models.IntegerField(default=0)
dislike = models.IntegerField(default=0)
image = models.FileField(blank=True, null=True)
created_date = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title[0:51]
class Reply(models.Model):
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
topic = models.ForeignKey(Topic, on_delete=models.CASCADE)
reply = models.TextField()
created_date = models.DateTimeField(auto_now=True)
def likes(self):
return Likes.objects.filter(reply=self, reply_flag=1).count()
likes.short_description = 'likes'
def dislikes(self):
return Likes.objects.filter(reply=self, reply_flag=-1).count()
dislikes.short_description = 'dislikes'
def __str__(self):
return self.reply
class Likes(models.Model):
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
reply = models.ForeignKey(Reply, on_delete=models.CASCADE)
reply_flag = models.CharField(max_length=5, choices=(
('0', 'No'), ('1', 'Positive'), ('-1', 'Negative'))) # 1 = vote up , -1 vote down
Views.py
# get all topics
def Topics(request):
topics = models.Topic.objects.all()
return render(request, 'Topics.html', {'topics': topics})
# get detail of specific topic
def TopicDetails(request, topic_id):
topic = get_object_or_404(models.Topic, pk=topic_id)
return render(request, 'Topic_Details.html', {'topic': topic, 'Likse': models.Likes.objects.all})
Templates:
topics.html :
{% for topic in topics %}
{% if topic.image}
<img src="{{topic.image.url}}"
{% endif %}
title : {{ topic.title }}
by : {{ topic.user }}
total agree : {{ topic.like }}
total not agree : {{ topic.dislike }}
{% endfor %}
topic.html :
topic title : {{ topic.title }}
{% for reply in topic.reply_set.all %}
reply : {{ topic.reply }}
by : {{ reply.user }}
total agree : {% for like in reply.lieks_set.all %} {% if like.reply == reply and like.reply_flag == '1' %} <!-- should be total of vote up --> {% endif %} {%endfor %}
total not agree : {% for like in reply.lieks_set.all %} {% if like.reply == reply and like.reply_flag == '-1' %} <!-- should be total of vote down --> {% endif %} {%endfor %}
{% endfor %}
I faced an issue with filter likes based on reply, user and reply flag (vote up, vote down) in topic.html,
I have two questions :
As my knowledge and as I read after search I couldn't filter data in template, So how could I show the filtered data in template based on reply, user and reply flag (vote up, vote down) ?
Is structure of app is correct ?
First of all, you should definitely make use of generic views (like DetailView or TemplateView). You have couple of options on how to include proper information, decide which is simpler for you:
Override a get_context of a generic view (and include aggregates in a template variable)
Override get_queryset of a view (inluding aggregates in a query)
Create a custom model manager and include appropriate aggregates in a queryset.
See aggregate and annotate for more information on how to count or sum dependent models.

django querysets in templates

I am trying to make specific queries by using some model entry fields.
I have the following model entry:
models.py
class Work(models.Model):
categories =(
('cat1', 'cat1'),
('cat2', 'cat2'),
('cat3', 'cat3'),
('cat4', 'cat4'),
('cat5', 'cat5'),
)
title = models.CharField(max_length=200)
description = RichTextUploadingField(config_name='awesome_ckeditor')
date = models.DateTimeField(default=timezone.now)
category = models.CharField(max_length=200, choices = categories, default = 'projects')
thumb = models.ImageField(upload_to = 'works/thumbs', blank = True)
content = models.FileField(upload_to = 'works/content_media', blank = True)
published = models.BooleanField()
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("work_detail",kwargs={'pk':self.pk})
#property
def thumb_url(self):
if self.thumb and hasattr(self.thumb, 'url'):
return self.thumb.url
#property
def content_url(self):
if self.content and hasattr(self.content, 'url'):
return self.content.url
here is the view:
views.py
class WorksListView(ListView):
template_name = 'template.html'
model = Work
def get_queryset(self):
return Work.objects.filter(published=True).order_by('-date')
and I am trying to query first by the category field then by entry in the following template:
template.html
{% for category in works_list.category %}
<ul data-category-name={{category.name}}>
{% for work in category.works %}
<li data-thumbnail-path={{thumbnail.url}} data-url={{content.url}} >
<div>
<p class="gallery1DecHeader">{{work.title}}</p>
<p class="gallery1DescP">{{work.description}}</p>
</div>
</li>
{% endfor %}
{% endfor %}
what do I need to change?
Okay, from what I can see there are a few problems. First, try adding context_object_name = 'works_list' That way you will be able to refer to the object_list as works_list like you do in the template outer for loop. The bigger problem is you are iterating over works_list.category, which according to your Work model is a Charlist(). I think you might be getting confused about what the choices kwarg does and expecting {% for category in works_list.category %} to iterate over your choices and giving you the list of cats you defined in categories. As far as I know, that's not how choices works.
If you go to your admin panel and add a new entry for your Work model, you'll see that category has a dropdown list that contains your list of cats. So, choices defines a set of legal category options for new Work objects, not a list in existing Work objects.
I think what you actually want is an additional model Category which defines: work = models.ForeignKey(Work, on_delete=models.CASCADE) as a one-to-many relationship. Basically, you want is for Work to have a subset of Category objects that you can iterate over. This will involve redesigning the way you structure and access your data though.
You need to change at least your views.py and template.html. Add a context_object_name and an extra context(Doc Link)
views.py
class WorksListView(ListView):
template_name = 'template.html'
model = Work
context_object_name = 'work_list'
def get_queryset(self):
return Work.objects.filter(published=True).order_by('-date')
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super(WorksListView, self).get_context_data(**kwargs)
# Insert categories so that it can be used in template
context['categories'] = Work.categories
return context
template.html
{% for category in categories%}
<ul data-category-name={{category.0}}>
{% for work in work_list %}
{% if category.0 == work.category %}
<li data-thumbnail-path={{work.thumb_url}} data-url={{work.content_url}} >
<div>
<p class="gallery1DecHeader">{{work.title}}</p>
<p class="gallery1DescP">{{work.description}}</p>
</div>
</li>
{% endif %}
{% endfor %}
</ul>
{% endfor %}

How can i get a value from forms.ModelChoiceField in django?

First of all I want to apologize for my English. It's hard for me to write this question in English, but I didn't find any ideas for my problem on russian sites. So, I want to create a timetable on school-site. In my models.py :
class Classes(models.Model):
class Meta:
db_table = 'classes'
verbose_name_plural = "School_classes"
verbose_name = "School_class"
name = models.CharField(max_length=50, unique=True, verbose_name = 'School_classes')
def __str__(self):
return self.name
class Lessons(models.Model):
class Meta():
db_table = "lessons"
verbose_name_plural = "Lessons"
verbose_name = "Lessons"
lessons_class = models.ForeignKey(Classes)
lessons_creationdate = models.DateField()
lessons_weekcontent = RichTextField()
Then, in forms.py I have:
class LessonsForm(forms.ModelForm):
classname = forms.ModelChoiceField(queryset = Classes.objects.all(),empty_label="Choose a class",widget=forms.Select(attrs={'class':'dropdown'}),label="School_classes")
class Meta:
model = Lessons
fields = ('lessons_class',)
And in my views.py:
def ShowTimetable(request):
LForm = LessonsForm(request.POST or None)
args = {}
args['classes'] = Classes.objects.all()
args['lessons'] = Lessons.objects.all()
args['showlessons'] = LForm
args.update(csrf(request))
if request.method == 'POST' and LForm.is_valid():
CurrentClass = LForm.cleaned_data('currentclass', None)
args['class_name'] = CurrentClass
args['lessons'] = Lessons.objects.filter(lessons_class = CurrentClass)
if args['lessons']:
return render_to_response('Weekcontentpage.html',args )
else:
return render_to_response('Weekcontentpage_null.html',args )
else:
return render_to_response('myview.html',args )
Finally, in myviews.html
{% extends 'base.html' %}
{% block content %}
<form method="post">
{% csrf_token %}
{{ showlessons }}
<input type="submit" value="Show timetable">
</form>
{% endblock %}
In Weekcontentpage.html:
{% extends "base.html" %}
{% block content %}
<h4>On request "{{ class_name }}:</h4>
{% for lesson in lessons %}
<h6>Date:{{ lesson.lessons_creationdate }}</h6>
<h4>{{ lesson.lessons_weekcontent }}</h4>
{% endfor %}
{% endblock content %}
and in Weekcontentpage_null.html:
{% extends "base.html" %}
{% block content %}
<h4> On "{{class_name}}" is nothing found :( (</h4>
{% endblock content %}
Now, after I make a choice in the drop down menu and push 'Show timetable' button, I've just see "None" and nothing is found :(. I understand that the problem in views.py, so i cant get a value from drop down, but I don't know how can i fix it. So i would appreciate any help. Thanks and sorry for my English:)
The same way as with any other field.
The problem is that you have defined a form class, but you are not using it in any way at all. Instead of ignoring the form and getting data from request.POST, you should be instantiating the form with the POST data, calling is_valid() on it, then getting the result from form.cleaned_data.

how to filter story by it's belonging tag

I have two models news and category, and in news I have foreignkey of category. I know how to display news with same category in a single template. but furthermore, in my home page I'm trying to display featured news of each category. this is where I'm having problem.
this is my models.py
class News(models.Model):
title = models.CharField(max_length=120)
content = models.TextField()
category = models.ForeignKey("Tag")
active = models.BooleanField(default=True)
featured = models.BooleanField(default=False)
top = models.BooleanField(default=False)
slug = models.CharField(max_length=255, unique=True)
featuredInCat = models.BooleanField(default=False)
objects = StoryManager()
class NewsQueryset(models.query.QuerySet):
def active(self):
return self.filter(active=True)
def featuredInCat(self):
return self.filter(featuredInCat=True)
class NewsManager(models.Manager):
def get_queryset(self):
return NewsQueryset(self.model, using=self._db)
def get_featuredInCat(self):
return self.get_queryset().active().featuredInCat()
def all(self):
return self.get_queryset().active()
class Category(models.Model):
title = models.CharField(max_length=120)
description = models.TextField(max_length=5000, null=True, blank=True)
In views.py
def category_list(request):
categoryList = NewsCategory.objects.all()
featuredInCat = News.objects.get_featuredInCat()
context = {
"featuredInCat":featuredInCat
"categoryList":categoryList,
}
return render(request,"news/category_list.html", context)
In my template
{% for category in categoryList %}
<div class='col-sm-4'>
<div id="container">{{category.title}}</h1>
<ul>
{% for x in featuredInCat %}
{{x.title}}</li>
{% endfor %}
</ul>
</div>
<hr>
</div>
{% endfor %}
then this shows the featuredInCat in every category where featuredInCat should be shown only in its Category section.
how do I fix this?
Take a look at the built-in regroup template tag of django. You will need to change your template to something like this:
{% regroup featuredInCat by category as news_list %}
<ul>
{% for news in news_list %}
<li>{{ news.grouper.title }}
<ul>
{% for item in news.list %}
<li>{{ item.title }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
You can change your for loop to iterate over the correct objects
{% for x in category.news_set.get_featuredInCat %}
You won't need the context variable anymore

How to use 2 ForeignKey filters one by one in 1 view - Django?

Hello and thank your for your answer:
My Taks: Show article, show 3 questions (related to this article), show 3 answer for each queston (related to these questions). Like a coomon test page.
My models:
class Step(models.Model): #Main article
title = models.CharField(max_length=200)
description = models.CharField(max_length=200)
annotation = models.TextField()
main_text = models.TextField()
def __str__(self):
return self.title
class Question(models.Model): #Questios related to Article.
step = models.ForeignKey(Step, on_delete=models.CASCADE)
title = models.CharField(max_length=200, default = "pages")
question_text = models.TextField()
question_name = models.CharField(max_length=40, help_text="английские буквы", blank=True, null=True)
class Answer(models.Model): #Answers related to Questions
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.TextField()
votes = models.IntegerField(default=0)
answer_name = models.CharField(max_length=40, help_text="английские буквы", blank=True, null=True)
How it should works
I use identificator in url, to show django which article it should show. Also it helps me to filtrs questions for this article. And then i should filted answers for each question, i have got previously. There are many articles, questions and answers, so you can't use objects().all.
url(r'^question(?P<question_id>[0-9]+)$', 'bakot.views.question', name='question'), #urls.py
def question(request, question_id):
stepfields = get_object_or_404(Step, id = question_id) #get an article
questionship = Question.objects.filter(step_id = question_id) #get questions, related to this article.
answership = questionship.prefetch_related().all #this is doesn't work. And i couldn't use coommon filter, as i don't know id for them. Or i could set ID and it will show the same answers for 3 questions.
context = {
"stepfieldst" : stepfields,
"questionship" : questionship,
"answership" : answership,
}
return render(request, 'bakot/question.html', context)
How i show it in template: (the part with questions ans answers)
{% block question_area %}
{% for question in questionship %}
<div class="small-12 medium-12 large-12 test-remark">
<legend><strong>{{ question.title }} </strong>{{ question.question_text }}</legend>
<ul class="menu vertical">
{% for answer in answership %}
<li>
<ul class="menu test-answer-padding navigation_hover_link11">
<li class="test-dot-padding"><input type="radio" name="{{ question.question_name }}" value="{{ answer.answer_name }}" id="pokemonRed" required></li>
<li><label for="pokemonRed">{{ answer.choice_text }}</label>
</ul>
</li>
{% endfor %}
</ul>
</div>
{% endfor %}
{% endblock %}
There are a few things I would do here to provide you the best solution.
First, you don't need to include questionship and answership in your context. Your template can get them via stepfields.questions and question.answers.
Next, to limit your list to 3, I would implement a template filter. This could be done using slices, like this:
register = template.Library()
#register.filter
def limit_to_3(list, arg):
return list[0:arg]
You could then, in your template, change your {% for %} loops to be this format:
{% for question in stepfieldst.questions|limit:3 %}
{% for answer in question.answers|limit:3 %}
{% endfor %}
{% endfor %}
Depending if your number of questions and answers per article are low enough that querying them all would be less burdensome than multiple queries, you could do something like this:
try:
stepfieldst = Step.objects.select_related(questions__answers).filter(id = question_id)
except Step.DoesNotExist:
raise Http404
This would select all related questions and answers in a single query.

Categories

Resources