Creating hierarchical urls in Django - python

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

Related

Views return html from another app in Django

I want to show a data with different feature .. So, there are 2 role where admin have 5 columns on the table. when the teacher only have 4 columns on the table. I change the HTML already but when I return classlist.html on teacherpage views.py .. it return the admin classlist.html that have 5 columns on the table.
Here is my code :
Urls.py (Teacher APP):
from django.urls import path
from teacherpage import views
urlpatterns = [
path('', views.index, name='index'),
path('classlist/', views.classlist, name='classlist'),
]
Views.py (Teacher APP):
def classlist(request):
data = classModel.objects.all()
classlist= {
"classlist" : data
}
return render(request,'classlist.html', classlist)
It is complicated without the actual codes of the project from you, but here is an idea about how you can use the same view and same html file for two different tables. For example, if your user's role is stored in the User model, then you can use this code in classlist.html:
{% if user.is_authenticated %}
{% if user.role == 'admin' %}
<table with five columns>
{% else %}
<table with four columns>
{% endif %}
{% else %}
no table for you
{% endif %}
FYI, you do not need to modify any views or urls to make it work.

Django 2.1 recalling old slug url variables

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 %}

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 generic model ListViews & forms

Following from my question Django sharing one model between two others which explored the best way to generically manage two similar models and their dependencies. I've now come to the next part - the views.
After a bit of tweaking around I've come to the following generic listview to represent the objects.
Is this coherent? Should the urls manage the models like this?
I believe if I refine their logic I can just subclass this itemlist and add additional logic in the future so it should be future-proofed.
A class that
urls.py excerpt
urlpatterns = [
url(r'^item/(?P<model>\w+)/$',views.ItemList.as_view(),name='generic'),
url(r'^item/(?P<model>\w+)/(?P<pk>\d+)$',views.ItemList.as_view(),name='generic'),
]
views.py excerpt
class ItemList(ListView):
context_object_name = 'itemlist'
template_name = 'food/item.html'
model = None
def get_queryset(self):
model = apps.get_model('food',self.kwargs.get('model'))
if self.kwargs.get('pk'):
print ('pk provided')
return model.objects.filter(pk=self.kwargs.get('pk'))
else:
print ('all')
return model.objects.all()
food/item.html excerpt (using registered filter to get class name for object)
{% block content %}
{% for item in itemlist %}
...
{% for review in item.reviews.all %}
{% endfor %}
...
<span class="glyphicon glyphicon-plus"> Add Review </span>
{% endblock %}
Also - can I carry this attitude into my forms (again assuming that when I add a review it'll generically link back to whatever object it came from?) or is that where I should start breaking them up?

detail view cant find pk

Fairly new to Django and Python, I am trying to build a detail view and a list view for a bunch of pictures I have uploaded. My list view works and shows all the pictures I have but I cannot figure out how to create a detailview that would let me look at only one picture.
In my "mysite" directory I have a url.py containing
urlpatterns = patterns('',
url(r'^photo/', include('photo.urls', namespace = "photo")),
)
Then in my "photo" directory I have
from photo import views
urlpatterns = patterns('',
url(r'$', views.ListImage.as_view(),name ='Photo-List',),
url(r'^/image/(?P<pk>\d+)/$', views.ImageView.as_view(),name='image-view',),
)
I have uploaded a bunch of pictures and I can see them when I visit my local website 800local../photo. But if I want to see one picture only, the address ../photo/image/1 returns a 404.
My Folder can be found at https://github.com/henrigeek/Django
List view will return object_list and Detail view return object.
{% if object %}
{{object.title}}
................
{% else %}
{% for img_obj in object_list %}
{{ img_obj.title }}
................
{% empty %}
No images found
{% endfor %}
{% endif %}
You can refer here Class based view

Categories