I have built a guide website.
Each guide is made of steps.
Each step is made of tasks.
To go the next step, you need to complete the task and then to the next, until there are no more steps.
Example views and URL:
/1 should show you guide1
/1/3 should show the step3 of guide1
/1/3/5 should show task5 of step3 in guide1
I want the URLs to be like this: /1/3/6 (guide1/step3/task6)
I got it to work when I go to /1. Then it shows the view of the guide.
But when I go to /1/1 or 1/1/1 I get a 404 error saying that the guide does not exist.
I need help. Here is my code:
Urls.py for app
urlpatterns = [
url(r'(?P<guide_id>[0-9]+)/$', views.taskoftheday, name="taskoftheday"),
url(r'(?P<guide_id>[0-9]+)/(?P<step.sequence_num>[0-9]+)/$', views.taskoftheday_step, name="taskoftheday_step"),
url(r'(?P<guide_id>[0-9]+)/(?P<step.sequence_num>[0-9]+)/(?P<task.sequence_num>[0-9]+)/$', views.taskoftheday_task, name="taskoftheday_task"),
]
urls.py for project
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^', include('registration.urls')),
url(r'^taskoftheday/', include('taskoftheday.urls')),
url(r'^', include('taskoftheday.urls')),
url(r'^analytics/', include('analytics.urls')),
url(r'^progress/', include('progress.urls')),
url(r'^goals/', include('goals.urls')),
url(r'^registration/', include('registration.urls')),
url(r'thanks/', views.thanks),
url(r'thanks_again/', views.thanks_again),
url(r'^$', views.landing_page),
]
models.py
class Guide(models.Model):
name = models.CharField(max_length=200)
guide_category = models.CharField(max_length=70)
guide_why = models.TextField()
guide_how = models.TextField()
is_complete = models.BooleanField(default=False)
def __unicode__(self):
return self.name
class Step(models.Model):
guide = models.ForeignKey(Guide, on_delete=models.CASCADE)
sequence_number = models.PositiveIntegerField(default=1)
name = models.CharField(max_length=10)
is_complete = models.BooleanField(default=False)
class Meta:
unique_together = ("guide", "sequence_number")
def __unicode__(self):
return self.name
class Task(models.Model):
step = models.ForeignKey(Step, on_delete=models.CASCADE)
sequence_number = models.PositiveIntegerField(default=1)
name = models.CharField(max_length=10)
task_img = models.ImageField()
task_task = models.TextField()
task_description = models.TextField()
is_complete = models.BooleanField(default=False)
class Meta:
unique_together = ("step", "sequence_number")
def __unicode__(self):
return self.name
views.py
def taskoftheday(request, guide_id):
try:
guide = Guide.objects.get(pk=guide_id)
except Guide.DoesNotExist:
raise Http404("Guide does not exist")
return render(request, 'taskoftheday/taskoftheday.html', {'guide': guide})
def taskoftheday_step(request, guide_id, step_id):
try:
guide = Guide.objects.get(pk=guide_id)
step = Step.objects.get(guide=guide, sequence_number=step_id)
except Step.DoesNotExist:
raise Http404("Step does not exist")
return render(request, 'taskoftheday/taskoftheday_step.html', {'step': step})
def taskoftheday_task(request, guide_id, step_id, task_id):
try:
guide = Guide.objects.get(pk=guide_id)
step = Step.objects.get(guide=guide, sequence_number=step_id)
task = Task.objects.get(step=step, sequence_number=task_id)
except Task.DoesNotExist:
raise Http404("Task does not exist")
return render(request, 'taskoftheday/taskoftheday_task.html', {'task': task})
Related
I've got a model of an article and everything works fine except when I change their status to draft - it disappears from Admin Django Panel. New articles are successfully added, but then don't show, the admin panel just can't access them. When I change the URL to force the admin panel to show me the details so I could edit it, I get a message that the article with the given ID doesn't exist. So basically every draft article gets lost. But I know they have to exist in my database because they show up on my article list view, but I can't go to detail view or draft view as I always get "No NewsModel matches the given query"
Django 2.0.5
models.py
class NewsModel(models.Model):
STATUS_CHOICES = (
('draft','Draft'),
('published','Published'),
)
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT)
title = models.CharField(max_length=250)
slug = AutoSlugField(populate_from='title')
body = models.TextField()
publish = models.DateTimeField(default=timezone.now)
created = models.DateTimeField(auto_now_add=True)
status = models.CharField(max_length=10, choices=STATUS_CHOICES)
image = models.ImageField(upload_to="news/")
description = models.TextField(null=True, blank=True)
def get_absolute_url(self):
from django.urls import reverse
return reverse('main:news_details', kwargs={'slug':self.slug})
def __str__(self):
return self.title
class Meta:
ordering = ('-publish',)
verbose_name = 'News'
verbose_name_plural = 'News'
admin.py
#admin.register(NewsModel)
class NewsAdmin(admin.ModelAdmin):
list_display = ('title', 'game', 'news_type', 'author', 'finish', 'publish')
views.py
def news_details(request, slug):
news = get_object_or_404(NewsModel, slug=slug)
news_aside = NewsModel.objects.filter(game=news.game).exclude(id=news.id)[:5]
return render(request, 'news/news_details.html', {'news':news, 'news_aside':news_aside, 'section':'news'})
def news(request):
""" List of all news """
news = NewsModel.objects.filter(status='published')[:3]
latest = news[0]
second = news[1]
third = news[2]
all_kind_news = NewsModel.objects.all()
return render(request, 'news/news.html', {'news':news, 'section':'news', 'all':all_kind_news, 'latest':latest, 'second':second, 'third':third, 'section':'news'})
def drafts(request):
""" List of all drafts """
news = NewsModel.objects.filter(status='draft')
paginator = Paginator(news, 9)
page = request.GET.get('page')
try:
news = paginator.page(page)
except PageNotAnInteger:
news = paginator.page(1)
except EmptyPage:
news = paginator.page(paginator.num_pages)
return render(request, 'news/news_list.html', {'news':news, 'section':'news', 'page':page})
urls.py (attaching just in case)
path('news/', views.news, name='news'),
path('news/<slug>', views.news_details, name='news_details'),
path('news/drafts', views.drafts, name='drafts'),
News_details, drafts, and admin panel throw 404 error while trying to access drafts, but the news list doesn't have that problem. The weirdest thing is that also admin panel is affected.
HI working on a new site using Django. can't seem to figure this bug out. First the intended site will be structured as;
Home page - Showing different languages with links to countries you can learn those languages in.
Click on a country on home page -> Country page
Country page will list all fo the schools that teach that language in that country.
Click on a school on country page -> School page.
I figured out this line of code in the Country page is causing the issue, but I don't know how to fix it
<a href="{% url 'schools' schools.id %}">
<div class="left"><h4>Test Link</h4></div>
</a>
This is the error I get in the browser
NoReverseMatch at /5/ Reverse for 'schools' with arguments '('',)' not found. 1 pattern(s) tried: ['(?P<country_id>[0-9]+)/(?P<schools_id>[0-9]+)/$']
Code from the project:
Models.py
from django.db import models
class Languages(models.Model):
language = models.CharField(max_length=100, blank=True, null=True)
country = models.ManyToManyField('Country', blank=True)
image = models.CharField(max_length=100, blank=True)
def __str__(self):
return self.language
class Country(models.Model):
country_name = models.CharField(max_length=50)
country_image = models.CharField(max_length=100, blank=True)
country_city = models.ManyToManyField('City', blank=True)
def __str__(self):
return self.country_name
class City(models.Model):
city_name = models.CharField(max_length=50)
city_image = models.CharField(max_length=1000, blank=True)
city_schools_in = models.ManyToManyField('Schools', blank=True)
def __str__(self):
return self.city_name
class Schools(models.Model):
school_name = models.CharField(max_length=100)
school_image = models.CharField(max_length=1000, blank=True)
school_country = models.ManyToManyField('Country', blank=True)
school_city = models.ManyToManyField('City', blank=True)
school_description = models.TextField()
school_accreditations = models.ManyToManyField('Accreditations', blank=True)
school_lpw = models.IntegerField()
school_cs = models.IntegerField()
school_course = models.ManyToManyField('CoursePrices', blank=True)
def __str__(self):
return self.school_name
class Accreditations(models.Model):
accreditation_name = models.CharField(max_length=50)
def __str__(self):
return self.accreditation_name
class CoursePrices(models.Model):
course_title = models.CharField(max_length=50, blank=True)
lessons_per_week = models.IntegerField()
class_size = models.IntegerField()
weekly_price = models.IntegerField()
language_level = models.CharField(max_length=50, blank=True)
def __str__(self):
return self.course_title
Views.py
from django.shortcuts import render
from django.http import Http404
from .models import Schools, CoursePrices, Languages, Country, City
def home(request):
languages = Languages.objects.all()
return render(request, 'home.html', {
'languages': languages,
})
def country(request, country_id):
try:
country = Country.objects.get(id=country_id)
except Languages.DoesNotExist:
raise Http404('Language not found')
return render(request, 'country.html', {
'country': country,
})
def schools(request, country_id, schools_id):
try:
schools = Schools.objects.get(id=schools_id)
except Schools.DoesNotExist:
raise Http404('school not found')
return render(request, 'schools.html', {
'schools': schools,
})
urls.py
from django.contrib import admin
from django.urls import path
from schools import views
urlpatterns = [
path('admin/', admin.site.urls),
path('', views.home, name='home'),
path('<int:country_id>/', views.country, name='country'),
path('<int:country_id>/<int:schools_id>/', views.schools, name='schools'),
]
Project structure screenshot
Any help would be greatly appreciated. Also please forgive any mistakes in posting or coding, still very new to coding and stack overflow / life in general :)
Your path named schools requires two arguments, you only passed one, so it failed to match any route.
Your comment on Rafael's answer that it is still not matching the path, even with two arguments provided, is because of the order of the paths in your urls.py file.
Django will go through the list of paths in order, and because a path with the single parameter country_id is found first it tries that but fails because you have a second parameter.
To fix that change the order of your paths
urlpatterns = [
path('admin/', admin.site.urls),
path('', views.home, name='home'),
# next two lines have been swapped.
path('<int:country_id>/<int:schools_id>/', views.schools, name='schools'),
path('<int:country_id>/', views.country, name='country'),
]
The 'schools' url needs two (2) arguments. You only pass one (1). In this case: schools.id
Django only finds a reverse match if you pass the correct amount of arguments. In this case, you should pass a country id AND a school id.
E.g. {% url 'schools' country_id=country.id schools_id=schools.id %} if you also have a country variable.
EDIT: '('',)' in your error message don't really look like integers. Are you sure the template variables exists and are integers?
I have an app for quiz. It shows registered quiz, but when I press submit button, It goes to /quiz/1/do/ to do function in views.py which should do this,
return HttpResponseRedirect(reverse('quiz.views.results', args=(q.id,)))
But it throws an error message,
NoReverseMatch at /quiz/1/do/
Reverse for 'quiz.views.results' not found. 'quiz.views.results' is not a valid view function or pattern name.
I wonder where could be a problem?
Code:
views.py:
from quiz.models import Quiz, Question, Score
from django.shortcuts import render, get_object_or_404
from django.http import HttpResponseRedirect, HttpResponse
from django.urls import reverse
from django.template import RequestContext
from django.contrib.auth.decorators import login_required
#login_required()
def index(request):
latest_quiz = Quiz.objects.all().order_by('-created')[:5]
return render_to_response('quiz/index.html', {'latest_quiz': latest_quiz})
def detail(request, quiz_id):
q = get_object_or_404(Quiz, pk=quiz_id)
context = {'quiz': q}
return render(request, 'quiz/detail.html', context)
def results(request, quiz_id):
return HttpResponse("You're looking at the results of quiz %s." % quiz_id)
def do(request, quiz_id):
q = get_object_or_404(Quiz, pk=quiz_id)
try:
answer = ''
for question in q.question_set.all():
answer += request.POST['q%d' % question.id]
except (KeyError, Question.DoesNotExist):
# Redisplaying the form
return render_to_response('quiz/detail.html', {
'quiz': q,
'error_message': "You didn't do the quiz %r " %request.POST,
}, context_instance=RequestContext(request))
else:
s = q.score_set.create(student=request.user.username, submit_answer=answer, score=100)
s.save()
return HttpResponseRedirect(reverse('quiz.views.results', args=(q.id,))) # HERE !!!
def not_found(request, exception=None):
response = render(request, '404.html', {})
response.status_code = 404
return response
def server_error(request, exception=None):
response = render(request, '500.html', {})
response.status_code = 500
return response
urls.py:
from .models import Quiz, Question, Score
from django.urls import path
from . import views as quiz_view
from . views import detail, results, do
from django.contrib.auth.decorators import login_required
app_name = 'quiz'
handler404 = 'quiz.views.not_found'
handler500 = 'quiz.views.server_error'
urlpatterns = [
path('', quiz_view.index, name='detail'),
path('<int:quiz_id>/', quiz_view.detail, name='detail'),
path('<int:quiz_id>/results/', quiz_view.results, name='results'),
path('<int:quiz_id>/do/', quiz_view.do, name='do'),
]
models.py:
from django.db import models
#from django.contrib.auth.models import User
from random import shuffle
class Quiz(models.Model):
""" Quiz model. Every quiz has 10 questions. """
title = models.CharField(max_length=100)
category = models.CharField(max_length=100)
description = models.TextField()
slug = models.SlugField(unique=True)
# author = models.ForeignKey(User, related_name='author')
author = models.CharField(max_length=50)
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
class Meta:
verbose_name_plural = 'quizzes'
ordering = ('-modified', 'created')
def __unicode__(self):
return u"%s" % self.title
def options(self):
return list('abcde')
class Question(models.Model):
""" Question model. Each question attached to exact one quiz. """
quiz = models.ForeignKey(Quiz, on_delete=models.PROTECT)
question = models.TextField()
answer = models.TextField()
choice1 = models.TextField()
choice2 = models.TextField()
choice3 = models.TextField()
choice4 = models.TextField()
class Meta:
ordering = ('id', 'question',)
def __unicode__(self):
return u"%s" % self.question
def get_options(self):
return {'answer': self.answer, 'choice1': self.choice1, 'choice2': self.choice2, 'choice3':self.choice3, 'choice4': self.choice4, }
def randomize_options(self):
options = ['answer', 'choice1', 'choice2', 'choice3', 'choice4', ]
shuffle(options)
return options
class Score(models.Model):
""" Score model. Every quiz taken by students are recorded here. """
quiz = models.ForeignKey(Quiz, on_delete=models.PROTECT)
student = models.CharField(max_length=50)
submit_answer = models.CharField(max_length=50)
score = models.IntegerField(default=0)
quiz_taken = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('quiz_taken', 'student', 'score',)
def __unicode__(self):
return u"%s %d" % (student, score)
It return this,
answer
'a'
q
<Quiz: Quiz object (1)>
question
<Question: Question object (1)>
quiz_id
1
request
<WSGIRequest: POST '/quiz/1/do/'>
s
<Score: Score object (4)>
change the line
return HttpResponseRedirect(reverse('quiz.views.results', args=(q.id,)))
to
return HttpResponseRedirect(reverse('quiz:results', args=(q.id,)))
The first argument of reverse must be 'viewname' Django tutorial
If you need to use something similar to the url template tag in your code, Django provides the following function:
reverse(viewname, url conf=None, args=None, kwargs=None, current_app=None)
You must use view name from 'urlpattern':
return HttpResponseRedirect(reverse('quiz:results', args=(q.id,)))
I think you should try this:
return HttpResponseRedirect(reverse('do', args=q.id))
models.py
class Match(models.Model):
match_name = models.CharField(max_length=100)
player = models.CharField(max_length=100, choices=match_game, default=2)
time_start = models.DateTimeField(blank=True, default=None, null=True)
match_finished = models.BooleanField(default=False)
def get_absolute_url(self):
return reverse('match:details', kwargs={'pk': self.pk})
def __str__(self):
return self.match_name
class PlayerSignup(models.Model):
current_player = models.ForeignKey(User)
signup = models.ForeignKey(Match)
urls.py
url(r'^create/add/$', views.MatchCreate.as_view(), name='match-add'),
url(r'^(?P<pk>[0-9]+)/$', views.DetailView.as_view(template_name = 'match/bracket_detail.html'), name='details'),
url(r'^search/$', views.IndexView.as_view(template_name = 'match/bracket.html'), name='search'),
url(r'(?P<pk>[0-9]+)/$', views.PlayerSign, name='join')
views.py
def PlayerSign(request):
model = PlayerSignup.objects.all()
match = Match.objects.get(pk=Match.pk)
joinmatch = PlayerSignup(current_player=request.user, signup=match)
joinmatch.save()
return render(request, 'match/bracket_detail.html', {'model': model })
template
Join Match
when a person clicks on the 'Join Match' link i would like it to create a PlayerSignup model and link it to the current match that they are on.
when i click the Join Match link nothing happens, no new model, no error
First, try to edit this statement
def PlayerSign(request):
...
match = Match.objects.get(pk=Match.pk)
to
def PlayerSign(request, pk):
...
match = Match.objects.get(pk=pk)
Because there is an request parameter in URL named pk, you should pass this parameter to the query method.
Second, review your url define
url(r'^(?P<pk>[0-9]+)/$', views.DetailView.as_view(template_name = 'match/bracket_detail.html'), name='details'),
url(r'(?P<pk>[0-9]+)/$', views.PlayerSign, name='join')
Change to
url(r'^match_detail/(?P<pk>[0-9]+)/$', views.DetailView.as_view(template_name = 'match/bracket_detail.html'), name='details'),
url(r'^player_detail/(?P<pk>[0-9]+)/$', views.PlayerSign, name='join')
Simplified version of forum app in Django. What I want to do is have an url in the form of forum/forum_slug/thread_slug/. I have no idea how to define and pass the custom forum_slug to urlpatterns.
# models.py
class Forum(models.Model):
title = models.CharField(max_length=60)
slug = models.CharField(max_length=60)
# ...
def threads(self):
_threads = Thread.objects.filter(forum=self)
return _threads
class Thread(models.Model):
title = models.CharField(max_length=60)
slug = models.CharField(max_length=60)
forum = models.ForeignKey(Forum)
# ...
def get_absolute_url(self):
return '/%s/%s' % (self.forum.slug, self.slug)
class Post(models.Model):
title = models.CharField('Title', max_length=60)
thread = models.ForeignKey(Thread)
# ...
# ******************************************************
# views.py
# ******************************************************
class ForumDetail(MetadataMixin, DetailView):
model = Forum
context_object_name = 'forum'
template_name = 'forum/forum.html'
name='forum'
# meta...
class ThreadDetail(MetadataMixin, DetailView):
model = Thread
context_object_name = 'thread'
template_name = 'forum/thread.html'
name = 'thread'
# meta...
# ******************************************************
# urls.py
# ******************************************************
urlpatterns = patterns('',
url(r'^$',
'forum.views.index',
name='index'
),
url(r'^(?P<slug>[a-zA-Z0-9-]+)/?$',
ForumDetail.as_view()),
# here it comes
url(r'^(?P<forum_slug>[a-zA-Z0-9-]+/?P<slug>[a-zA-Z0-9-]+)/?$',
ThreadDetail.as_view()),
)
I assume that you want URL pattern for slugs. Below is the example you can try.
# URL example: /forum/this-is-a-forum-1/this-is-a-thread-1/
url(r'^forum/(?P<forum_slug>[\w-]+)/(?P<thread_slug>[\w-]+)$', ThreadDetail.as_view()),
Hope this helps.
#rayy: Thanks. No, this is not what I was looking for -- I simply do not know how to define forum_slug in it. That's what I was asking for. :-) Well, I figured out kinda more verbose solution but, frankly, I do not like it:
# models.py
from django.core.urlresolvers import reverse
class Thread(models.Model):
#... like before
def get_absolute_url(self):
return reverse('thread_url', (), {'forum_slug': self.forum.slug, 'slug': self.slug})
# urls.py
urlpatterns = patterns('',
# ...
url(r'^(?P<forum_slug>[\w-]+)/(?P<slug>[\w-]+)/$', ThreadDetail.as_view(), name='thread_url'),)
# index.html / forum.html (in a loop)
{{thread.title}}