I am working on a django project(Django v2.0) which has users from different groups, this group is set up within the user profile. I would like to make the website more personal and have the user's group at the start of the website's url (added in through a slug), after they login.
Ideally once they login they would then be redirected to the right page with that slug at the beginning of the url. Within the login page I access the user's group, this group is called and will from now on be referred to as troop, to minimise confusion with Django groups. Here's my login class post view where I retrieve this:
def post(self, request):
def normal_user(user):
return user.groups.filter(name='Normal_User').exists()
username = request.POST['username']
password = request.POST['password']
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
if normal_user(user):
redirecting_url = 'accounts:home'
elif user.is_superuser:
redirecting_url = 'admin:index'
slug = user.userprofile.troop
return redirect(redirecting_url, slug=slug)
else:
form = AuthenticationForm()
error = True
args = {'form': form, 'error': error}
return render(request, self.template_name, args)
In this case I am trying to access the url "account" which I have called "home" and is in my app "accounts".
My home function in views.py in the app accounts has this code:
def home(request, slug):
args = {'user': request.user}
return render(request, 'accounts/home.html', args)
I do not want to do anything with the slug except display it in the url.
My template view looks like this:
<div class="container">
<br>
<h2><strong>Your Progress:</strong></h2><br>
<h3>
<strong>50% progress</strong>
<div class="progress">
<div class="progress-bar bg-danger progress-bar-striped progress-bar-
animated" role="progressbar" style="width:50%" aria-valuenow="50" aria-
valuemin="0" aria-valuemax="100">50%</div> </div>
</div></h3>
<br><br>
{% endblock %}
I also have a link to 'home' within my navbar and I link it in the similar fashion than the link above, using {% url 'accounts:home' slug = instance.slug %}
I'm currently having the following error:
"NoReverseMatch at /BC/account/
Reverse for 'home' with keyword arguments '{'slug': ''}' not found. 1 pattern(s) tried: ['(?P[-a-zA-Z0-9_]+)/account/$']"
The slug in this case is 'BC'.
My urls.py look like this:
In the root folder:
main_urls = [
path('leaders/admin/', admin.site.urls),
path('account/', include('accounts.urls', namespace='accounts'))
]
urlpatterns = [
path('', include('home.urls', namespace='home_page')),
path('login/', include('login.urls', namespace='login')),
path('<slug:slug>/', include(main_urls))
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
And my urls.py in my accounts app looks something like this:
app_name="accounts"
urlpatterns = [
path('', views.home, name="home")
]
Sorry for the long description, but I've been reading every possible site/video I could find on Django slugs and have not been able to find anything which works yet. Could someone please help me with this problem?
Your regular expression for your url requires the slug to be at least one character long. However, the exception you're getting suggests that the troop name (which is used as the slug named argument) is empty:
Reverse for 'home' with keyword arguments '{'slug': ''}'
If the user isn't required to have a troop, in which case you want to just redirect him to /accounts/ instead of /troop/accounts, I suggest you add a separate URL for just accounts/$, or tweak the regular expression to allow an empty troop.
After poking around my code I found something which works. This is as it seems to be that I should be able to have views which take in a slug argument whilst still working if the slug is empty. To fix this all I did was change the slug part in my view function definitions to **kwargs.
Then I added a varaiable which accessed what the slug was and passed that through my templates for when I have a link.
For example:
def home(request, **kwargs):
slug = request.user.userprofile.troop
args = {'slug_arg': slug}
return render(request, 'accounts/home.html', args)
My links in my templates then look like this: {% url 'accounts:home' slug=slug_arg %}
Edit
I have found that the problem was that during my rendering, I should be able to pass through the slug, and in this case slug=instance.slug was not working and was sometimes coming up as being empty. However if I have it at slug=request.user.userprofile.troop then this works without having to accept an argument from the view.
In having said such, I am unable to do this for the admin site as I do not know how to access the views.py for the admin and thus add the parameter to take in the slug.
Related
I've dug around the internet and can't find a solution. Please help me lovely people of the internet.
In my views.py
#login_required
def edit_todo(request, pk):
usertodo = get_object_or_404(Todo, pk=pk)
return HttpResponse('test')
In my urls.py
urlpatterns = [
...
path('edit-todo/<int:pk>/', views.edit_todo, name='edit-todo'),
path('test/<int:pk>/', views.edit_todo, name='test'),
...
]
In my template/component that's included
<form hx-encoding="multipart/form-data" hx-post="{% url 'core:edit-todo' tododetail.todo.id %}" hx-target="#todo-list" method="post">
tododetail.todo.id is called because I've got an ordering table which has todo & user as foreign keys.
When accessing the view directly using a test URL it works
first post so please forgive my ignorance as this is my first django app.
I am trying to create a template that displays all of the information regarding a specific "Ticket" from a list of all open tickets.
Unfortunately I am receiving following message whenever I attempt to add an anchor with a template url tag:
NoReverseMatch at /tickets/tasks/ Reverse for 'order' with arguments
'('',)' not found. 1 pattern(s) tried:
['tickets/order/(?P<ticket_id>[^/]+)/$']
Error message updated. Please see Update below.
And it is ONLY on this one HTML Template.
Below is all of the code I believe will be able to shed some light into the issue:
models.py:
from django.db import models
# Create your models here.
class Ticket(models.Model):
"""A basic support ticket"""
# User ticket title.
ticket_Name = models.CharField(max_length=50)
# When the request was submitted.
ticket_Submitted = models.DateTimeField(auto_now_add=True)
#Ticket Type
ticketTypeChoices=[
('Update', 'Article Edit/Update'),
('Addition', 'New Content/Article Request'),
('Typo', 'Article Typo/Formatting Issue'),
('Issue', 'Website Error/Issue'),
('Other', 'Other'),
]
# Type of ticket (Update, Addition, Typo, Site Issue)
ticket_Type = models.CharField(
max_length=50,
choices=ticketTypeChoices,
default= 'Other'
)
# Users Name
ticket_Contact = models.CharField(max_length=50)
# User Email (for follow up)
ticket_Email = models.EmailField(max_length=254)
# Article URL (if applicable)
ticket_URL = models.CharField(blank=True, max_length=254)
# User description of the issue.
ticket_Description = models.TextField()
#Ticket Status Choices
StatusChoices = [
('Pending', 'Pending'),
('Open', 'Open'),
('Complete', 'Complete'),
('Deferred', 'Deferred'),
('Awaiting Response', 'Awaiting Response'),
]
# Status of the Ticket
ticket_Status = models.CharField(
max_length=50,
choices=StatusChoices,
default= 'Pending'
)
# Comments from HelpDesk Staff
ticket_Comments = models.TextField(blank=True )
#Shows when the ticket was last saved.
ticket_Last_Updated = models.DateTimeField(auto_now=True)
def __str__(self):
"""Return a string representation of the model"""
return self.ticket_Name
views.py:
# Imports Models from the app
from . models import *
# Imports from the Forms List
from . forms import TicketForm
# Create your views here.
# View of all active tickets
def ticket(request):
tickets = Ticket.objects.all().order_by('-ticket_Submitted')
context = {'ticket': tickets}
return render(request, 'tickets/joblist.html', context)
# User can view details about a Ticket
def order(request, ticket_id):
order = Ticket.objects.get(id=ticket_id)
context= {'order': order}
return render(request, 'tickets/tix.html', context)
urls.py
from django.urls import path,include
from . import views
app_name='tickets'
urlpatterns = [
# Include default auth urls.
path('', include('django.contrib.auth.urls')),
# Support Ticket Form
path('submit/', views.submit, name='submit'),
# Contact Us Form
path('contact/', views.contact, name='contact'),
# TicketWeblist
path('tasks/', views.ticket, name='tasks'),
# Ticket Details
path('order/<str:ticket_id>/', views.order, name='order' )
]
Template (joblist.html):
{% for tickets in ticket %}
<tr>
<td>{{tickets.ticket_Name}}</td>
<td>{{tickets.ticket_Type}}</td>
<td>{{tickets.ticket_Contact}}</td>
<td>{{tickets.ticket_Status}}</td>
<td>{{tickets.ticket_Submitted}}</td>
<td>{{tickets.ticket_Last_Updated}}</td>
<td><a class="btn btn-sm btn-info" href="{% url 'tickets:order' ticket.id %}">View</a>
</tr>
{% endfor %}
After reviewing the code a dozen time, all I can be sure of is that is an issue that begins with the template anchor template url tag. (View) but no matter what format I try it comes up with this or a similar error.
UPDATE: At Mel's suggestion changed the url 'order' to 'tickets:order' and am now receiving the following message:
NoReverseMatch at /tickets/tasks/ Reverse for 'order' with arguments
'('',)' not found. 1 pattern(s) tried:
['tickets/order/(?P<ticket_id>[^/]+)/$']
I have been attempting to resolve this issue for about three days and was determined to solve it myself. Any type of help is appreciated and please feel free to point out any spaghetti code or lack of notes as well as I am looking for ways to grow.
Thanks!
You've set a namespace for your urls: app_name = 'tickets'
So correct reverse url would be.
{% url 'tickets:order' tickets.id %}
Can you try changing your order view function to this -
def order(request, ticket_id):
active_order = Ticket.objects.get(id=ticket_id)
context= {'order': active_order}
return render(request, 'tickets/tix.html', context)
You have created a separate urls.py for you app (it looks like it), so be sure to include namespace = tickets in your project urls.py file. And then in your template, you should do as follows:
{% url 'tickets:order' ticket.id %}
In other words, you need to include the name of the app as well.
I just saw that you are passing ticket.id from your template to the view, however there is no ticket.id anywhere in the code. Why don't you try passing a value that is there in the template. It should work.
Sorry if the title is unclear, I'm not sure the best way to describe the issue. I have an application with a Ticket model and a Team model. All Tickets are associated with a single Team. The issue I'm having is a problem of URL reversing. I'm trying to set it up my URLs like so: /<team_pk>/tickets/ displays a list of tickets associated with the Team specified by team_pk. So /1/tickets/ would display all of the tickets for the first Team. Both of these objects are in the app tracker.
To do this, I've set up my project/urls.py files like so:
project/urls.py
urlpatterns = [ path('<team_pk>/', include('tracker.urls', namespace='tracker')), ]
tracker/urls.py
urlpatterns = [ path('tickets/', views.TicketTable.as_view(), name='ticket_list'), ]
Then, inside my html templates, I have the following URL tag:
href="{% url 'tracker:ticket_list' %}"
This results in a NoReverseMatch error:
NoReverseMatch at /1/tickets/
Reverse for 'ticket_list' with no arguments not found. 1 pattern(s) tried: ['(?P<team_pk>[^/]+)/tickets/$']
What I would like is for the reverse match to just use the current value for the team_pk URL kwarg.
What I have tried to fix it:
I have found the following solution to the problem, but it involves a lot of repetition, and I feel like there must be a DRYer way.
First, I extend the get_context_data() method for every view on the site.
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['current_team_pk'] = self.kwargs['team_pk']
return context
Then I reference this context in every URL template tag:
href="{% url 'tracker:ticket_list' team_pk=current_team_pk %}"
This results in the desired behavior, but it's a lot of repetition. So, is there a better way?
Edit:
Based on Willem Van Onsem's suggestion, I changed the URL template tag to href="{% url 'tracker:ticket_list' team_pk=team_pk %}", referencing the URL kwarg directly. But this doesn't seem to be working reliably. On the index page /<team_pk>/ loads just fine, and it includes two relevant URLs: /<team_pk>/ and /<team_pk>/tickets/. When I navigate to /<team_pk>/tickets/, however, I get another NoReverseMatch error:
NoReverseMatch at /1/tickets/
Reverse for 'home' with keyword arguments '{'team_pk': ''}' not found. 1 pattern(s) tried: ['(?P<team_pk>[^/]+)/$']
It seems the URL kwarg <team_pk> is not being passed for some reason. But the only link to 'home' is part of my base.html, which the other templates are extending. So the relevant template tags are the same.
Edit 2:
The view in question:
class TicketTable(LoginRequiredMixin, SingleTableMixin, FilterView):
table_class = my_tables.TicketTable
template_name = 'tracker/ticket_list.html'
filterset_class = TicketFilter
context_object_name = 'page'
table_pagination = {"per_page": 10}
PAGE_TITLE = 'Open Tickets'
TICKET_STATUS_TOGGLE = 'Show Closed Tickets'
TICKET_STATUS_TOGGLE_URL = 'tracker:closed_ticket_list'
DISPLAY_DEV_FILTER = True
DISPLAY_STATUS_FILTER = True
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['page_title'] = self.PAGE_TITLE
context['ticket_status_toggle'] = self.TICKET_STATUS_TOGGLE
context['ticket_status_toggle_url'] = self.TICKET_STATUS_TOGGLE_URL
context['display_dev_filter'] = self.DISPLAY_DEV_FILTER
context['display_status_filter'] = self.DISPLAY_STATUS_FILTER
return context
def get_queryset(self):
return models.Ticket.objects.filter_for_team(self.kwargs['team_pk']).filter_for_user(self.request.user).exclude(status='closed')
Edit 3:
I found a solution to access the URL kwargs without modifying context data. I'm not sure why team_pk=team_pk didn't work in the URL tag, but team_pk=view.kwargs.team_pk does work.
Based on the comments and responses from Willem Van Onsem, a friend of mine, and some of my own digging, I found what I think is the DRYest way to do what I was trying to do. I created a custom mixin:
class CommonTemplateContextMixin:
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
if self.kwargs.get('team_pk'):
context.setdefault('team_pk', self.kwargs.get('team_pk'))
else:
context.setdefault('team_pk', self.request.user.teams.all()[0].pk)
return context
Then I subclass this mixin with all my views. Then I have a team_pk template tag inside all my templates, and I just add team_pk=team_pk to all my URL template tags. The only advantage to using this instead of team_pk=view.kwargs.team_pk is that I can add some additional logic for the case when the URL kwarg isn't available.
Use Django 1.10.4. I have a model Stream, for which I created CreateView. When objects are created through the admin panel everything works fine, but when I use the form CreateView, an object is created (either in admin or in the database is no different from the other), but attempts to provide a link to it through DetailView result in an error:
NoReverseMatch at /
Reverse for 'detail_stream' with arguments '()' and keyword arguments '{'pk': 17}' not found.
2 pattern(s) tried: ['(?P<pk>[0-9])/$', 'streams/(?P<pk>[0-9])/$']
This error occurs when displaying the ListView, and then only for an object created through CreateView.
The place where the error occurs:
{% for item in stream_list %}
<a href="/streams{% url "detail_stream" pk=item.id %}">
...
</a>
{% endfor %}
When you try to go directly to DetailView (http://127.0.0.1:8000/streams/17) 404 error.
urls.py:
from django.conf.urls import url
from .views import StreamDetail, StreamUpdate
urlpatterns = [
url(r'^$', StreamList.as_view(), name='streams'),
url(r'^(?P<pk>[0-9])/$', StreamDetail.as_view(), name='detail_stream'),
url(r'^(?P<pk>[0-9])/update/$', StreamUpdate.as_view()),
]
Also, the url for the streams added to the main site urlpatterns.
View:
class StreamCreate(LoginRequiredMixin, CreateView):
login_url = '/login/'
def form_valid(self, form):
regex = re.compile('[^a-zA-Z]')
newtags = []
for tag in form.cleaned_data['tags']:
tag = regex.sub('',tag)
newtags.append(tag)
form.cleaned_data['tags'] = newtags
return super(StreamCreate,self).form_valid(form)
def form_invalid(self, form):
print(form.errors)
return super(StreamCreate,self).form_invalid(form)
def get_success_url(self):
return reverse('streams')
I suspect that something I did not realize at CreateView, but I can not understand that and need your help.
Your regex in the given route is wrong.
url(r'^(?P<pk>[0-9])/$', StreamDetail.as_view(), name='detail_stream')
[0-9] means it expects a single-digit number. 17 has two digits, so the regexp needs to take that into account (add + there)
url(r'^(?P<pk>[0-9]+)/$', StreamDetail.as_view(), name='detail_stream')
Some other routes in there have the same issue.
my task is to create on main page of my web site two list one list for my post
and second list categories titles which belong my post.
i create that and work fine,and i create post details connect and again work fine.
but i cant to work category details if i want to see list from my post which belong specific category i cant show me error page not found.
my code
my model
class Category(models.Model):
categorytitle =models.CharField(max_length=1,choices=CAT_CHOICES,unique=True)
slug= models.SlugField()
class Posts(models.Model):
Title = models.CharField(max_length=100,blank=True)
slug= models.SlugField()
category = models.ManyToManyField(Category)
my view category
def view_category(request, slug):
category = get_object_or_404(Category, slug=slug)
return render_to_response('blog/view_category.html', {
'category': category,
'posts': Posts.objects.filter(category=category)
})
my urls category
url(r'^(?P<slug>[^\.]+)/$', views.view_category, name='view_category'),
main template tags
{% for category in categories %}
<li>{{ category.categorytitle }}</li>
{% endfor %}
error message
Page not found (404)
Request Method:
GET
Request URL:
http://127.0.0.1:8000/category1/
Raised by:
blog.views.view_post
No Posts matches the given query.
my view post
def view_post(request, slug):
return render_to_response('blog/movies_details.html', {
'post': get_object_or_404(Movies,slug=slug)
})
my urls view
url(r'^(?P<slug>[^\.]+)/$', views.view_post, name='view_post'),
if i use browser db for sqlite view
Change your regex in urls.py to:
url(r'^(?P<slug>[\w-]+)/$', views.view_category, name='view_category'),
\w = alphanumeric signs + underscore
- = hyphen
(These characters are now allowed in the slug)
And change the Post filter to:
Posts.objects.filter(category_id=category.id)
NOTE:
Posts filtering have to placed before rendering, not in it (do it in the same way like "category")
How do you create slugs in the Category model? In admin? Manually or automatically via prepopulated_fields? Because I don'ลง like in the categorytitle field the max_length=1
If your error message shows: "Raised by: blog.views.view_post" Than obviously django is hitting view_post function in your views and not view_category.
Due to wrong function call view_post can't find the post with slug:"category1" so gives a 404 error ( obviously!! ).
So i will suggest to check out if there is a url mismatch that is causing this first.
So I had a similar problem, did all I could by reading various solutions and none was helpful. My solution was real funny(ironic) since I spent an hour to find out what was wrong.
In the urls.py, the order of the url s is pretty important.
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^', include('shop.urls')),
url(r'^shpcart/', include('shpcart.urls')),
]
The above pattern kept saying 404 shpcart/ not found, but shpcart was already there.
Just as I was about to find myself trying to persuade the pc, I moved the shpcart url 1 line above, everything started to sound. If anyone is stuck like I was, hope this helps
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^shpcart/', include('shpcart.urls')),
url(r'^', include('shop.urls')),
]