Django 2.1 recalling old slug url variables - python

I am having some issues directing a url pattern through the following type of path: Listview --> Listview2 --> DetailView. I am running into trouble with my url patterns. Here is what I am working with:
app_name = 'ism'
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
path('<slug:client_slug>/', views.CostCenterListView.as_view(), name='cost_center_list'),
path('<slug:client_slug>/<slug:cost_center_slug>/', views.cost_center_detail, name='cost_center_detail'),
]
The home page of this app is a list of all clients. Clicking on a client will populate a new page showing a list of that client's sub-clients (cost_center).
Here is part of my template {% url %} call to my final path listed above (/slug/slug/):
{% for cost_center in cost_centers %}
<ul>
<li>{{ cost_center }}</li>
</ul>
{% endfor %}
Adding this along with its accompanying view causes an error:
NoReverseMatch at /ism/cleint_slug/
Can you confirm that my issue has to deal with my {% url %} in my template not remembering the first slug in my url path? My error message seems to indicate that it's trying to find:
.../cost_center_slug
instead of:
.../client_slug/cost_center_slug/
My assumption is that django would magically remember the first part of my url pattern (ie client_slug), but that does not appear to be happening. Do I need to bring in more context variables in my view to allow for the calling of two url variables (also is url variable the right terminology? It doesn't sound right) in my template above?
Here is my full error message ('cffd' is a slug representing a cost-center):
Reverse for 'cost_center_detail' with arguments '('cffd',)' not found.
1 pattern(s) tried:
['ism/(?P<client_slug>[-a-zA-Z0-9_]+)/(?P<cost_center_slug>[-a-zA-Z0-9_]+)/$']
Here is my views.py. I was initially trying to work with a DetailView and its get_object method, but I couldn't get that to work in addition to the function based view I shown
class IndexView(generic.ListView):
template_name = 'ism/index.html'
context_object_name = 'client_list'
def get_queryset(self):
queryset = Client.objects.all()
return queryset
class CostCenterListView(generic.ListView):
template_name = 'ism/costcenter_list.html'
context_object_name = 'cost_centers'
def get_queryset(self):
slug = self.kwargs.get('client_slug')
client = Client.objects.get(slug=slug)
queryset = client.costcenter_set.all()
return queryset
def cost_center_detail(request, client_slug, cost_center_slug):
cost_center = get_object_or_404(CostCenter, slug=cost_center_slug)
context = {'cost_center': cost_center}
return render(request, 'ism/costcenter_detail.html', context)

I think you've got a wrong url. It should be either
{% url 'ism:cost_center_list' client_slug %}
or (you don't provide enough argument to construct cost_center_detail url)
{% url 'ism:cost_center_detail' client_slug cost_center.slug %}

Related

Django Reverse for 'document' with keyword arguments {'title':'computer science'} not found. 1 pattern tried

i getting a NoReverseMatch exception but i can't see my mistake.
Urls file:
url(r'^Demo$', views.demo, name='demo'),
url(r'^Demo/(?P<title>[\w-]+)/$', views.demo_document, name='demo_document'),
url(r'^Document_list$', views.document_list, name='document_list'),
Template:
{% for demotext in demotexts %}
<li>{{ demotext.title }}</li>
{% endfor %}
Views:
def demo(request):
demotexts = DemoText.objects.all().order_by('date')
return render(request, 'keywordExtraction/demo.html', {'demotexts': demotexts})
def demo_document(request, title):
demotext = DemoText.objects.get(title=title)
demotexts = DemoText.objects.all().order_by('date')
return render(request, 'keywordExtraction/demo.html', {'demotext': demotext, 'demotexts': demotexts})
Message:
Reverse for 'demo_document' with keyword arguments '{'title': 'Computer Science'}' not found. 1 pattern(s) tried: ['KeywordExtraction/Demo/(?P[\w-]+)/$']
/views.py in demo
return render(request, 'keywordExtraction/demo.html', {'demotexts': demotexts})
Local vars
Variable Value
demotexts <QuerySet [<DemoText: DemoText object (4)>, <DemoText: DemoText object (5)>]>
request <WSGIRequest: GET '/KeywordExtraction/Demo'>
The [\w-]+ does not match whitespace. This pattern is used for slugs [Django-doc]. A slug is a way to render text pleasantly in the browser, since a whitespace is rendered as %20, whereas a hyphen is rendered as -.
In order to make a slug, you can make use of a SlugField [Django-doc], or a AutoSlugField [readthedocs], from the django-autoslug package [readthedocs]. django-autoslug is probably more convenient.
You can install it in your local environment with:
pip install django-autoslug
then you can add a slug to your model:
from autoslug import AutoSlugField
class DemoText(models.Models):
title = models.CharField(max_length=128, unique=True)
slug = AutoSlugField(populate_from='title')
A SlugField will by default also add a db_index on the column, to allow fast retrieval.
then in your url you can match it, probably it is better to rename the parameter to slug to avoid confusion:
url(r'^Demo/(?P<slug>[\w-]+)/$', views.demo_document, name='demo_document'),
In the view, you can then match on the slug:
def demo_document(request, slug):
demotext = DemoText.objects.get(slug=slug)
demotexts = DemoText.objects.all().order_by('date')
return render(request, 'keywordExtraction/demo.html', {'demotext': demotext, 'demotexts': demotexts})
and in the template, you render it with slug:
{% for demotext in demotexts %}
<li>{{ demotext.title }}</li>
{% endfor %}
Likely you will need to populate the database again to generate the slugs.

Django - No Reverse Match Error - URL only works with static values

I'm working on a Django site that displays a list of projects. You go to a page, you see a project, you click it, and you can then see project details and have the option to edit the page.
For each individual project, I use a template called project.html. Then on that page, I have a link to edit_project.html
Edit Project
Whenever I try to load the project page to view, I get this error:
Reverse for 'edit_project' with arguments '('',)' not found. 1
pattern(s) tried: ['edit_project/(?P\d+)/$']
I checked the urls, and they seemed fine. So, I tried hard-coding a project id that I knew was in the database. For example, I called:
Edit Project
instead of calling that same thing with "project.id". When I did that, the error went away.
Why does this work with a hard-coded value instead of a project.id variable?
I also tried deleting the database and all the migrations in case something strange was happening there. I got the same issue though.
Here is the code I used to set everything up in case it is helpful.
project.html
{% extends "profile/base.html" %}
{% block content %}
<p>
Edit Project
</p>
<p>Status: {{ status }}</p>
{% endblock content %}
edit_project.html
{% block content %}
<p>{{ project }}</p>
<p>Edit project:</p>
<form action="{% url 'profile:edit_project' project.id %}" method='post'>
{% csrf_token %}
{{ form.as_p }}
<button name="submit">Save Changes</button>
</form>
{% endblock content %}
views.py
#login_required
def edit_project(request, project_id):
"""Edit an existing project"""
project = Project.objects.get(id=project_id)
#Make sure the project belongs to the owner
if project.owner != request.user:
return Http404
if request.method != 'POST':
#Initial request; pre-fill form with the current entry
form = ProjectForm(instance=project)
else:
#POST data submitted; process data
form = ProjectForm(instance=project, data=request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('profile:project',args=[project.id]))
context = {'project':project, 'form':form}
return render(render, 'profile/edit_project.html', context)
(project) forms.py
class DateInput(forms.DateTimeInput):
input_type = 'date'
class ProjectForm(forms.ModelForm):
class Meta:
model = Project
fields = ['name','description','status', 'project_type', 'start_date','end_date', 'due_date']
labels = {'name':'Name', 'description':'Description:', 'status':'Status', 'project_type':'Project Type',
'start_date':'Start Date', 'end_date':'End Date', 'due_date': 'Due Date',}
widgets ={'description':forms.Textarea(attrs={'cols':80}),'start_date':DateInput(),
'end_date':DateInput(),'due_date':DateInput()}
urls.py
urlpatterns = [
#Home page
url('^$', views.index, name='index'),
#Show all projects
url('projects/$', views.projects, name='projects'),
#Details for single project
url('^projects/(?P<project_id>\d+)/$', views.project, name='project'),
#Page for editing a single project
url('^edit_project/(?P<project_id>\d+)/$', views.edit_project, name='edit_project'),
]

Error using DjangoFramework in template

new try of dev here.
Im trying to make a project and I alredy having some issues that i dont know why dont work... I put my code and explain it...
url.py
app_name = 'opotest'
urlpatterns = [
url(r'^$', views.indexView, name='index'),
url(r'^inicio/$', views.ListaView.as_view(), name='inicio'),
url(r'^test/(?P<tipo>.+)/$', views.TestList.as_view(), name='test'),
url(r'^test/(?P<tipo>.+)/run/$',
views.TestDetail.as_view(), name='run'), # this one
View.py
class TestDetail(generic.DetailView):
model = Pregunta
context_object_name = 'lista'
def get_queryset(self):
return Pregunta.objects.all()
HTML template
{% for test in lista %}
<br/>
<p>Pregunta: {{ pregunta.textopregunta }}</p>
{% endfor %}
Models.py
class Pregunta(models.Model):
id = models.AutoField(primary_key=True)
textopregunta = models.CharField('Texto pregunta', max_length=1000)
test = models.ForeignKey(Test, on_delete=models.CASCADE)
def __str__(self):
return self.textopregunta
This code should bring me some 'pregunta' that i have alredy created but it doesnt work... can you please tell me what im doing wrong? the for bring me Pregunta: the textopregunta do not appears...
Thanks everyone
D...
Should be
{% for test in lista %}
<br/>
<p>Pregunta: {{ test.textopregunta }}</p>
{% endfor %}
will work,
but anyway, if you want to use Pregunta.objects.all() , you must use ListView, not DetailView. Like this
class TestList(generic.ListView):
model = Pregunta
context_object_name = 'lista'
{% for test in lista %}
<br/>
<p>Pregunta: {{ test.textopregunta }}</p>
{% endfor %}
UPDATE
If you want to list all your model objects, please use ListView.
1. Change your view to ListView
class TestList(generic.ListView):
model = Pregunta
context_object_name = 'lista'
Then you can use objects and lista both in tempalte.
2. Change your url
You don't need tipo in url, if it's listview.
urlpatterns = [
url(r'^$', views.indexView, name='index'),
url(r'^inicio/$', views.ListaView.as_view(), name='inicio'),
url(r'^test/(?P<tipo>.+)/$', views.TestList.as_view(), name='test'),
url(r'^test/run/$',
views.TestList.as_view(), name='run'), # this one
3. use objects or lista in templates.
Because you define lista in context_object_name : it means your objects list will be used with lista in template. (you can use objects cause django ListView automatically make context for you)
{% for test in lista %}
<br/>
<p>Pregunta: {{ test.textopregunta }}</p>
{% endfor %}
UPDATE for DetailView
1. Change urls with pk
Above all, you have to understand about View - Template and urls.
In your urls - you should pass params what you want to use to grep your one specific object. It should be unique, so just use pk(id). (Or you can make your own unique slug)
url(r'^test/run/$',
views.TestList.as_view(), name='run'), # this one
# this is DetailView
url(r'^test/(?P<pk>\d+)/$',
views.TestDetail.as_view(), name='run'), # this one
Then your url will be.. test/1/ , test/2/.
2. change views
Actually, django CBV supports many functions (method) so you don't have to handle more but it's hard to understand.
class TestDetail(generic.DetailView):
model = Pregunta
context_object_name = 'lista'
You're confusing when you don't know about DetailView.
In DetailView, (as you can see here-ccbv.co.kr ) it has get_object() method. If any url_kwargs defined in your view, it use pk for basic. So it will find like Pregunta.objects.get(id=self.kwargs.get(pk)) that takes from your urls.py.
Then you can use your object in template, using lista or object.
<br/>
<p>Pregunta: {{ lista.textopregunta }}</p>
You DONT have to forloop all objects (actually CANT) because DetailView basically find your object from your kwargs (in this situation, pk).
I highly recommend reading django docs (CBV) and seeing ccbv.co.kr for understanding CBV, or trying to use FBV in django.
try to override the get_context_data() method, as below then change your template also,
class TestDetail(generic.DetailView):
model = Pregunta
context_object_name = 'lista'
def get_queryset(self):
return Pregunta.objects.all()
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['sample'] = self.get_queryset()
return context
Try to change your template as below,
{% for test in sample %}
<br/>
<p>Pregunta: {{ test.textopregunta }}</p>
{% endfor %}
By default Generic.DetailView looks for pk in the url parameters which is used to search data from your database. In your case you are using tipo as url parameters. So, you need to override the default inside your view. Your code should be something like this:
class TestDetail(generic.DetailView):
model = Pregunta
context_object_name = 'lista'
pk_url_kwarg = 'tipo'
def get_queryset(self):
return Pregunta.objects.all()
Now it will
look for tipo in your url and take the parameters to search from your database. More on Generic views can be found on this link: https://ccbv.co.uk/projects/Django/1.10/django.views.generic.detail/DetailView/

django. Passing id from one template to second template

I need to pass id from one template to another template. In template i am iterating over one model
{% for project in all_projects %}
<h3>{{ project.name }}</h3>
{% endfor %}
This going to one template where my url looks like
url(r'^$', views.ProjectsListView.as_view(), name='index'),
url(r'^platforms/$', views.PlatformsIndexView.as_view(), name='platforms'),
url(r'^platforms/nodes/$', views.PlatformsNodesListView.as_view(), name='platforms_list'),
Browser url that i have is http://127.0.0.1:8000/platforms/?project=1
that's ok good. But from second template i need to send third template another parametrs and filters. So how do i can get id of project?
I can not send now project id to third template because i am not iterating over it. How to remember id of project?
views.py
class ProjectsListView(ListView):
template_name = 'project/projects.html'
model = Project
context_object_name = 'all_projects'
class PlatformsIndexView(TemplateView):
template_name = 'project/platforms.html'
class PlatformsNodesListView(ListView):
template_name = 'project/general.html'
model = Platform
context_object_name = 'all_platforms'
def get_queryset(self):
queryset = super().get_queryset()
type_filter = self.request.GET.get('type')
project_filter = self.request.GET.get('project')
if type_filter in [Platform.BACKEND, Platform.ANDROID, Platform.IOS, Platform.FRONTEND]:
queryset = queryset.filter(type=type_filter)
if project_filter:
queryset = queryset.filter(project__id__exact=project_filter)
else:
raise Http404
return queryset
Please explain me.
Thank you in advance

Creating hierarchical urls in Django

I'm dabbling in django for the first time and I'm stuck on one single issue and it's driving me crazy. I'm trying to create a set of pages with a hierarchical url like this www.example.com/{state}/{county}. Basically the problem I'm having is that I can get www.example.com/{state}, but I don't know how to use the url system in django to carry the state over to the state/county page. What I end up getting is www.example.com//{county}
urls.py
app_name = 'main'
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^(?P<pk>[A-Z]{2})/$', views.StateView.as_view(), name='state'),
url(r'/(?P<pk>[a-zA-Z]*)/$', views.CountyView.as_view(), name='county'),
]
views.py
def index(request):
return render(request, 'main/index.html', {})
class StateView(generic.ListView):
template_name = 'main/state.html'
context_object_name = 'county_list'
def get_queryset(self):
counties = [ // list of a couple counties for testing purposes]
return counties
class CountyView(generic.ListView):
template_name = 'main/county.html'
context_object_name = 'water_list'
def get_queryset(self):
return WaWestern.objects.filter(water_name__contains='Orange') // hard coded for easy testing
index.html
this file is large so I'll just show an example of one of my state links
<a id="s06" href="CA">
state.html
{% if county_list %}
<ul>
{% for county in county_list %}
<li>{{ county }}</li>
{% endfor %}
</ul>
{% else %}
<p>No counties were found.</p>
{% endif %}
I realize this can all be solved by adding a column in my db for the state but I'm 100% sure this can be solved pretty simply, I'm just not sure how
Your url pattern for county is slightly off:
url(r'^(?P<state_pk>[A-Z]{2})/(?P<county_pk>[a-zA-Z]*)/$', views.CountyView.as_view(), name='county')
Hierarchical URL patterns would work with inclusions. Here, it is not a nested URL structure, so it would not match the county, followed by state unless you have a regex pattern to match that.
Also, note the change of the regex pattern name - you might have to tweak your views and templates accordingly

Categories