Overview / Problem:
Hi! The wrong template and view are loading every time I click the check_tier_level link in my template.
When that parameter is in, it loads the home view with "check_tier_level" as the special_message, even though my links go to the view for check_tier_level. If I click any of the form buttons to grant access, the proper message shows up in that spot. I just can't check the level.
The app works fine and renders the right template / view only when I remove the special_message parameter from the urlpattern and view.
The only other lead I have on this is that the url in the browser will also look like http://127.0.0.1:8000/tiered_access_app/Tier 1 granted!/, instead of having the characters escaped with %20 and so on.
My goal
The whole reason I want to keep that parameter in is so a special_message can notify users of the latest update based on their actions. If anyone knows a better way to do this without making a whole new view / template (which I know is a solution, and how to do it), I'd like to know how. Anyways, here's my code:
urlpatterns.py
path('', views.home, name='home'),
path('<str:special_message>/', views.home, name='home_special_message'),
path('check_tier_level/', views.check_tier_level, name='check_tier_level'),
path('check_tier_level/gain_access/', views.gain_access, name='gain_access'),
views.py
def home(request, special_message=None):
return render(request, 'tiered_access_app/home.html', {'special_message': special_message})
def check_tier_level(request):
current_user = request.user
try:
find_user = TieredAppCustomUser.objects.get(user=current_user)
if find_user.tier_choice == 'tier1':
return render(request, 'tiered_access_app/check_tier_level.html', {'level_1': 'You have access to level 1.'})
# and so on with other levels...
except ObjectDoesNotExist:
pass
return render(request, 'tiered_access_app/check_tier_level.html', {'no_access': 'You don\'t have access to the content here yet.'})
home.html
{% if special_message %}
<h2>{{ special_message }}</h2>
{% endif %}
<form action="{% url 'tiered_access_app:gain_access' %}" method="POST">
{% csrf_token %}
<label>Check level 1 access</label>
<!-- *******PROBLEM WITH LINK HERE******** -->
<p>Try to access level 1 first. You won't be allowed unless you gain access first, by clicking the button below.</p>
<!-- *******PROBLEM WITH LINK HERE******** -->
<input type="hidden" value='1' name="tier_level">
<input type="submit" value="Enable level 1">
</form>
I FIGURED IT OUT:
All I had to do was change my url patterns into the following order:
path('', views.home, name='home'),
path('check_tier_level/', views.check_tier_level, name='check_tier_level'),
path('check_tier_level/gain_access/', views.gain_access, name='gain_access'),
path('<str:special_message>/', views.home, name='home_special_message'),
The only difference here and what I have below, is the position of the 2nd function that goes to home. I'm going to leave this question up in case someone else comes across this same problem. I don't know why this made it work, but it did. Now everything works perfectly.
Related
I am simply trying to open the web app to the home page, but at startup I am given the NoReverseMatch error message. The full message is the following: Reverse for 'wiki' with no arguments not found. 1 pattern(s) tried: ['wiki/(?P<title>[^/]+)/$']. In case it's relevant, I am using Django version 3.2.4.
In urls.py for my project I have:
urlpatterns = [
path('', include("encyclopedia.urls", namespace="encyclopedia")),
path('admin/', admin.site.urls),
]
In urls.py for my app I have:
app_name = "encyclopedia"
urlpatterns = [
path("", views.index, name="index"),
path("wiki/<title>/", views.entry, name="wiki"),
.... (rest omitted for brevity)
]
In views.py I have:
def index(request):
context = {
"entries": ["item1", "item2", "item3"],
"form": SearchForm(),
}
return render(request, "encyclopedia/index.html", context)
In index.html, I have:
{% block body %}
<h1>All Pages</h1>
<ul>
{% for entry in entries %}
<li>
<form action="{% url 'encyclopedia:wiki' %}", method="POST">
{% csrf_token %}
<input type="text" value="{{ entry }}" name="link" hidden>
<input type="submit" class="link-btn" value="{{ entry }}" style="border: 0; background-color: white">
</form>
</li>
{% endfor %}
</ul>
{% endblock %}
As the error message indicates, it appears to be looking at the url pattern named wiki, and then subsequently failing to find the arguments passed to it. However, I am not trying to check that pattern; it should be going to the default pattern of path("", views.index, name="index"), not the wiki one. The wiki one works fine, by the way, as when I go the url wiki/<title>/, it loads fine. The rest of the app works fine as well. The other odd thing is that the index path worked fine before I added the arguments to the wiki url (path("wiki/<title>/", views.entry, name="wiki"),).
I have been looking at other SO posts that deal with this issue, and have followed the debugging advice given in this post, as well as this article, and none of the solutions apply/seem to work; this happens on app startup so there is no link being clicked to begin with, there are no comments it could be reading instead, it's not supposed to be calling wiki in the first place so the key word arguments are irrelevant, and the namespace is set in the project's urls.py. In summary, the issue appears to be that, upon start up of the app, it should be looking at the name "index" in the first path(), and then calling the appropriate function, but it is instead looking at the name "wiki" and expecting arguments.
If anyone can figure out how I can fix this problem, I would be very grateful!
I've been trying to figure this out for a while now but I feel like I don't know the framework well enough to debug this myself.
Basically I'm creating a little blog style site and I'm trying to create a list of posts which can link to the page to read the post itself.
I have a for loop in my template:
templates/home.py
<h1>Home Page</h1>
<p>welcome to the ven home page, {{ username }}!</p>
Click here to log out
<br>
Click here to create a post
<h2>Posts:</h2>
{% for post in posts %}
<div>
<hr>
<h4>{{post.title}}</h4>
<p>{{post.body}}</p>
<p><i>{{post.tags}}</i></p>
</div>
{% endfor%}
It's the line <h4>{{post.title}}</h4> which is causing the problem. I'm getting the error
Reverse for 'show' with keyword arguments '{'id': 1}' not found. 1
pattern(s) tried: ['posts/(?P<post_id>\\d+)/view/$']
here is my urls file
url(r'^$', views.CreateFormView.as_view(), name='create'),
url(r'^(?P<post_id>\d+)/view/$', views.show_post, name='show')
The create method link works fine
and here is the view which loads the template:
def home(request):
if not request.user.is_authenticated:
return redirect('users:login')
posts = Post.objects.all()
username = request.user.username
return render(request, 'ven/home.html', {'username': username, 'posts':
posts})
If more information is needed then let me know and I will provide it.
All other answers have said that this error is to do with the namespace, but it's working fine with the create link so I'm stumped.
Thanks in advance!
The argument names are mismatching.
You'd want to change <h4>{{post.title}}</h4>
to
<h4>{{post.title}}</h4>
Since in urls.py the show url is defined as '^(?P<post_id>\d+)/view/$'.
I am a beginner at Django development, and I am trying to make a food diary application. After a user enters his email on index.html, another web page should be rendered according to whichever button he clicks.
I can possibly add two templates, but I also want my app to work if a user manually types a valid URL such as /apps/<user_email>/addDiaryEntry/. I don't know what to add in /apps/urls.py. Also, can I somehow access a user object's Id so my routing URL become /apps/<user_id>/addDiaryEntry/ instead?
/templates/apps/index.html
<form method="post" action="/apps/">
{% csrf_token %}
<label for="email_add">Email address</label>
<input id="email_add" type="text">
<button type="submit" name="add_entry">Add entry</button>
<button type="submit" name="see_history">See history</button>
/apps/views.py
def index(request):
if request.POST:
if 'add_entry' in request.POST:
addDiaryEntry(request)
elif 'see_history' in request.POST:
seeHistory(request)
return render(request, 'apps/index.html');
def addDiaryEntry(request):
print ("Add entry")
def seeHistory(request):
print ("See history")
/apps/urls.py
urlpatterns = [
url(r'^$', views.index, name='index'),
]
Thank you for your help! Please feel free to share any best practices which I am not following.
1) passing in an argument into a url, you can use regex groups to pass arguments. Here is an example using a kwarg:
url(r'^(?P<user_email>[^#]+#[^#]+\.[^#]+)/addDiaryEntry/$', views.add_diary, name='add-diary-entry'),
2) just render a different template depending on which button was pressed:
def index(request):
if request.POST:
if 'add_entry' in request.POST:
addDiaryEntry(request)
return render(request, 'apps/add_entry.html');
elif 'see_history' in request.POST:
seeHistory(request)
return render(request, 'apps/see_history.html');
It's always tough starting out, make sure you put in the time to go over the docs, here are some places to look over regarding these topics:
https://docs.djangoproject.com/en/1.10/topics/http/urls/#named-groups
https://docs.djangoproject.com/en/1.10/topics/http/views/
I am running into a few issues regarding URL mappings in Django. I have the following code:
table.html:
<form id="filter_form" method="post" action="update_filters/">
<input type="submit" name="submit" value="Report" />
</form>
urls.py:
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^update_filters/', views.filter_report, name='update_filters'),
]
views.py:
def filter_report(request):
# Code in the function
return render(request, 'autotester/table.html', context)
and everything works, but when I hit the "Report" button multiple times I get:
127.0.0.1:8000/autotester/update_filters
127.0.0.1:8000/autotester/update_filters/update_filters
127.0.0.1:8000/autotester/update_filters/update_filters/update_filters
etc
and I have no idea what's causing it. There has to be some sort of simple fix for this but I just can't find it and I have been trying to figure this out for 3 hours now and my brain is just fried.
Try using {% url 'update_filters' %} template tag. And also add $ at the end of the regular expression in your url definition.
url(r'^update_filters/$', views.filter_report, name='update_filters'),
I'm trying to build a simple website with login functionality very similar to the one here on SO.
The user should be able to browse the site as an anonymous user and there will be a login link on every page. When clicking on the login link the user will be taken to the login form. After a successful login the user should be taken back to the page from where he clicked the login link in the first place.
I'm guessing that I have to somehow pass the url of the current page to the view that handles the login form but I can't really get it to work.
EDIT:
I figured it out. I linked to the login form by passing the current page as a GET parameter and then used 'next' to redirect to that page. Thanks!
EDIT 2:
My explanation did not seem to be clear so as requested here is my code:
Lets say we are on a page foo.html and we are not logged in. Now we would like to have a link on foo.html that links to login.html. There we can login and are then redirected back to foo.html.
The link on foo.html looks like this:
<a href='/login/?next={{ request.path }}'>Login</a>
Now I wrote a custom login view that looks somewhat like this:
def login_view(request):
redirect_to = request.REQUEST.get('next', '')
if request.method=='POST':
#create login form...
if valid login credentials have been entered:
return HttpResponseRedirect(redirect_to)
#...
return render_to_response('login.html', locals())
And the important line in login.html:
<form method="post" action="./?next={{ redirect_to }}">
So yeah thats pretty much it, hope that makes it clear.
You do not need to make an extra view for this, the functionality is already built in.
First each page with a login link needs to know the current path, and the easiest way is to add the request context preprosessor to settings.py (the 4 first are default), then the request object will be available in each request:
settings.py:
TEMPLATE_CONTEXT_PROCESSORS = (
"django.core.context_processors.auth",
"django.core.context_processors.debug",
"django.core.context_processors.i18n",
"django.core.context_processors.media",
"django.core.context_processors.request",
)
Then add in the template you want the Login link:
base.html:
Login
This will add a GET argument to the login page that points back to the current page.
The login template can then be as simple as this:
registration/login.html:
{% block content %}
<form method="post" action="">
{{form.as_p}}
<input type="submit" value="Login">
</form>
{% endblock %}
To support full urls with param/values you'd need:
?next={{ request.get_full_path|urlencode }}
instead of just:
?next={{ request.path }}
This may not be a "best practice", but I've successfully used this before:
return HttpResponseRedirect(request.META.get('HTTP_REFERER','/'))
Django's built-in authentication works the way you want.
Their login pages include a next query string which is the page to return to after login.
Look at http://docs.djangoproject.com/en/dev/topics/auth/#django.contrib.auth.decorators.login_required
I linked to the login form by passing the current page as a GET parameter and then used 'next' to redirect to that page. Thanks!
I encountered the same problem. This solution allows me to keep using the generic login view:
urlpatterns += patterns('django.views.generic.simple',
(r'^accounts/profile/$', 'redirect_to', {'url': 'generic_account_url'}),
)
In registration/login.html (nested within templates folder) if you insert the following line, the page will render like Django's original admin login page:
{% include "admin/login.html" %}
Note: The file should contain above lines only.
See django docs for views.login(), you supply a 'next' value (as a hidden field) on the input form to redirect to after a successful login.
You can also do this
<input type="hidden" name="text" value="{% url 'dashboard' %}" />