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.
Related
I am creating a simple system using Django Sqlite but I am facing this error whenever i try to open the table as an admin in the django/admin by clicking Studends table. The error is the following:
OperationalError at /admin/student/student/
no such column: student_student.course_id
I searched allot but could not find any exact solution to my problem.
The following is my code.
views.py
from django.shortcuts import render
from .models import Student
# Create your views here.
def index(request):
return render(request, "student/index.html",{
"student": Student.objects.all()
})
index.html
{% extends "student/layou.html" %}
{% block body %}
<h2>Student information</h2>
<ul>
{% for student in Student %}
<li> {{ student.id }} Student Full Name: {{ student.f_name }}{{ student.l_name }} in {{ student.grade }} with {{ student.gpa }} in {{ student.course_id }}</li>
{% empty %}
No information entered
{% endfor %}
</ul>
{% endblock %}
models.py
from django.db import models
# Create your models here.
class Course(models.Model):
code = models.CharField(max_length=10)
course_name = models.CharField(max_length=64)
def __str__(self):
return f"Course name: {self.course_name} with course code ({self.code})"
class Student(models.Model):
f_name = models.CharField(max_length=64)
l_name = models.CharField(max_length=64)
course = models.ForeignKey(Course, on_delete=models.CASCADE, related_name= "Classes" )
grade = models.CharField(max_length=10)
gpa = models.DecimalField(max_digits=4.0, max_length=4, decimal_places=2)
def __str__(self):
return f"{self.id} Full Name: {self.f_name} {self.l_name} in {self.grade} with a gpa {self.gpa} in course {self.course_id}"
You cannot refer to Course object via Student object with that:
{{ student.course_id }}
You can get to object or it's id like that:
{{ student.course }} # returns related Course object
{{ student.course.id }} # returns related Course object's id
For future reference, you also want to make more changes:
"student": Student.objects.all()
# change to:
"students": Student.objects.all()
{% for student in Student %}
# change to:
{% for student in students %}
{% extends "student/layou.html" %}
# probably change to:
{% extends "student/layout.html" %}
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.
I am trying to link the author of a post two his profile page, but when I click the on the link, get refered two /profiles/ not to the id of the author.
My views.py looks like this:
def userpage(request, id):
profil = get_object_or_404(UserProfile, pk=id)
context = {'profil': profil}
return render(request, 'gaestebuch/userpage.html', context)
My urls.py looks like this:
url(r'^profiles/(?P<id>[0-9]+)/$', views.userpage, name='userpage')
And the html part where I want to have the link looks like this:
{% for e in latest_eintrage_list %}
<li>
<div id="comment_main">
---> {{ e.author }}
<br>
</div>
{{ e.title }}
<br>
<div id="comment_main">
Comments: {{ e.comments.count }} | {{ e.created_date }} | {{ e.get_typ_display }}
</div>
{% if not forloop.last %}
<hr>
{% endif %}
</li>
{% endfor %}
The part marked with an arrow is the part, where I wanted the link to the author to be.
models.py:
class UserProfile(models.Model):
user = models.OneToOneField(User)
info = models.CharField(max_length=200, blank = False, default=('keine Angabe'))
class Eintrag(models.Model):
author = models.ForeignKey('auth.User')
title = models.CharField(max_length=200)
text = models.TextField()
NEED = 'ND'
GIVE = 'GV'
TYP_CHOICES = (
(NEED, 'Need'),
(GIVE, 'Give'),
)
typ = models.CharField(max_length=2, choices= TYP_CHOICES, default=NEED)
created_date = models.DateTimeField(default=timezone.now)
I am receving the following error-message:
Reverse for 'userpage' with arguments '('',)' and keyword arguments '{}' not found. 1 pattern(s) tried: [u'gaestebuch/profiles/(?P<id>[0-9]+)/$']
I am glad for any help :)
Inside the {% for e in latest_eintrage_list %} loop, you do have a variable profil. Therefore profil.id is treated as the empty string, and the url tag fails.
You can follow the foreign key from Eintrag.author foreign key to the User model, then follow the one to one field backwards to the UserProfile model:
{{ e.author }}
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.
I'm stuck on my next step of showing the query from the database to the html template. I'm able to put some basic information, but I got stuck on the foreign key queries.
Here is sample of my code:
Here is my model:
class Player_Bios(models.Model):
my_id = models.SlugField(unique=True)
player_id = models.IntegerField(primary_key=True, max_length=50)
name = models.CharField(max_length=50)
last = models.CharField(max_length=50)
def __unicode__(self):
return self.player_id
class BatStat (models.Model):
player_id = models.ForeignKey('Player_Bios')
team_id = models.ForeignKey('Team')
bat_stat_id = models.CharField(max_length=50, unique=True)
sport_code = models.CharField(max_length=50, blank=True)
ab = models.IntegerField(max_length=50, null=True)
def __unicode__(self):
return self.bat_stat_id
My View:
def SpecificPLayer(request, playerslug):
player = Player_Bios.objects.get(player_id=playerslug) #this is the name, last and it is working fine
playerStat = BatStat.objects.filter(player_id=playerslug) #Here I'm calling the foreign key
print playerStat
context = {'player' : player, 'today' : date.today(), 'playerStat' : playerStat }
return render_to_response ('singleplayer.html', context, context_instance=RequestContext(request))
My HTML Template:
{% extends 'base.html' %}
{% block content %}
<div id="singleplayer">
<p>Name: {{ player.name|capfirst }}</p>
<p>Last Name: {{ player.last|capfirst }}</p>
</div>
{% endfor %}
{% endblock %}
Now when I do print playerStat, I get all of the BatStat from the player_id. In y case I get the following:
[<BatStat: 40539520011>, <BatStat: 40539520021>, <BatStat: 40539520031>]
I get the result that I want on the shell by doing the following:
playerStatID=BatStat.objects.filter(player_id='the player id here')
print playerStatID
[<BatStat: 40539520011>, <BatStat: 40539520021>, <BatStat: 40539520031>]
for i in playerStatID:
playerStat= BatStat.objects.get(bat_stat_id=i)
print BatStat.ab
200
So by doing that I can get the information that I need it, now how can I get that, but to put it on the template. I can't use a loop on the template to get a query, so I guess the loop has to be done on the view, but how. Thanks
Since you have a ForeignKey between BatStat and Player_Bios, you can use a batstat_set to get all related BatStats for the single player.
[Docs for _set here.][1]
So you would have your views.py as:
def SpecificPLayer(request, playerslug):
player = Player_Bios.objects.get(player_id=playerslug) #this is the name, last and it is working fine
batstats = player.batstat_set.all()
context = {'player' : player, 'today' : date.today(), 'batstats': batstats, }
return render_to_response ('singleplayer.html', context,context_instance=RequestContext(request))
and in your template:
{% for stat in batstats %}
{{ stat.ab }}
{% endfor %}