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/
Related
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 %}
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
In the following code, How does the template details.html knows that album is passed to it by views.py although we have never returned or defined any context_object_name in DetailsView class in views.py.
Please explain how are the various things getting connected here.
details.html
{% extends 'music/base.html' %}
{% block title %}AlbumDetails{% endblock %}
{% block body %}
<img src="{{ album.album_logo }}" style="width: 250px;">
<h1>{{ album.album_title }}</h1>
<h3>{{ album.artist }}</h3>
{% for song in album.song_set.all %}
{{ song.song_title }}
{% if song.is_favourite %}
<img src="http://i.imgur.com/b9b13Rd.png" />
{% endif %}
<br>
{% endfor %}
{% endblock %}
views.py
from django.views import generic
from .models import Album
class IndexView(generic.ListView):
template_name = 'music/index.html'
context_object_name = 'album_list'
def get_queryset(self):
return Album.objects.all()
class DetailsView(generic.DetailView):
model = Album
template_name = 'music/details.html'
urls.py
from django.conf.urls import url
from . import views
app_name = 'music'
urlpatterns = [
# /music/
url(r'^$', views.IndexView.as_view(), name='index'),
# /music/album_id/
url(r'^(?P<pk>[0-9]+)/$', views.DetailsView.as_view(), name='details'),
]
Thanks in advance !!
If you check the implementation of get_context_name(), you'll see this:
def get_context_object_name(self, obj):
"""
Get the name to use for the object.
"""
if self.context_object_name:
return self.context_object_name
elif isinstance(obj, models.Model):
return obj._meta.model_name
else:
return None
And the implementation for get_context_data() (from SingleObjectMixin):
def get_context_data(self, **kwargs):
"""
Insert the single object into the context dict.
"""
context = {}
if self.object:
context['object'] = self.object
context_object_name = self.get_context_object_name(self.object)
if context_object_name:
context[context_object_name] = self.object
context.update(kwargs)
return super(SingleObjectMixin, self).get_context_data(**context)
So you can see that get_context_data() adds to the dictionary an entry with the key context_object_name (from get_context_object_name()) which returns obj._meta.model_name when self.context_object_name isn't defined. In this case, the view got self.object as a consequence of the call to get() which calls get_object(). get_object() takes the model that you've defined and automatically queries it from your database using the pk you've defined in your urls.py file.
http://ccbv.co.uk/ is a very good website for seeing all of the functions and attributes the class based views of Django has to offer in a single page.
This can be helpful where if context_object_name is not set, the context name will be constructed from the model_name of the model that the queryset is composed from
https://docs.djangoproject.com/en/3.1/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectMixin.get_context_object_name
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?
So I'd like to think what I'm doing is fairly common. I'm attempting to display a result set using Django. I have looked online for a while and here is what I've come up with:
models.py{
from django.db import models
from django.conf import settings
class SalesRep(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL)
class Sales(models.Model):
seller = models.ForeignKey(SalesRep)
sold_on = models.DateField("Sold On")
}
sales_view.py{
from salesteam.models import SalesRep, Sales
from django.views.generic import ListView
class SellerHome(List View):
model = SalesRep
template_name = 'production/sales.html'
#property
def rep_sales(self):
return Sales.objects.filter(SalesRep=self)
}
sales.html{
<div id="total-sales">
{% for sale in SellerHome.rep_sales%}
<li>{{ sale.id }}</li>
{% empty %}
<li>You don't currently have any sales</li>
{% endfor %}
</div>
}
For the sake of completeness I even tried writing just the property out as Sales.objects.all() but still no luck. Thanks for taking a look as I'm fairly new to HTML, Django, and Python. Any help on what I'm doing wrong would be much appreciated. Let me know if you have any questions :)
I'm not sure what tutorial you've followed, but there is a lot of errors in your code... I'm assuming you would like to display all Sales for the logged in user?
In this scenario, I would change the model slightly to add a related_name to Sales foreign key to SalesRep:
class SalesRep(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL)
class Sales(models.Model):
seller = models.ForeignKey(SalesRep, related_name='sales')
sold_on = models.DateField('Sold On')
Documentation: https://docs.djangoproject.com/en/1.7/ref/models/fields/#django.db.models.ForeignKey.related_name
And I would change the views to use DetailView:
from django.views.generic import DetailView
class SellerDetailView(DetailView):
model = SalesRep
template_name = 'production/sales.html'
context_object_name = 'seller'
def get_object(self):
return self.request.user
Docs on DetailView — https://docs.djangoproject.com/en/1.7/ref/class-based-views/generic-display/#detailview
<div id="total-sales">
<ul>
{% for sale in seller.sales.all %}
<li>{{ sale.id }}</li>
{% empty %}
<li>You don't currently have any sales</li>
{% endfor %}
</ul>
</div>
First, I'd recommend avoiding class based views, at least as you are learning Django, since they are not really necessary and needlessly complicated for what you are doing.
Anyway, to answer your question using class-based views, your problem is in your template and your view. You'll want to put your rep_sales logic in a get_queryset, set the model to be Sales, not SalesRep, and then reference object_list in the template. More info.
However, I'd instead recommend writing a normal, function-based Django view. Something like this might get you started:
def view_all_sales(request):
my_sales_rep = SalesRep.objects.get(request.user)
all_my_sales = Sales.objects.filter(seller=my_sales_rep)
return render(request, "production/sales.html", {
"sales": all_my_sales
})