When I try to use DetailView to view my posts I keep getting an exception error.
ImproperlyConfigured at /post/1/
BlogDetailView is missing a QuerySet. Define BlogDetailView.model, BlogDetailView.queryset, or override BlogDetailView.get_queryset().
Request Method: GET
Request URL: http://127.0.0.1:8000/post/1/
Django Version: 2.2
Exception Type: ImproperlyConfigured
Exception Value:
BlogDetailView is missing a QuerySet. Define BlogDetailView.model, BlogDetailView.queryset, or override BlogDetailView.get_queryset().
Exception Location: C:\Users\julia.virtualenvs\Documents-SYi_ANcG\lib\site-packages\django\views\generic\detail.py in get_queryset, line 73
Python Executable: C:\Users\julia.virtualenvs\Documents-SYi_ANcG\Scripts\python.exe
Python Version: 3.7.3
I have reviewed my code against the book Django For Beginners by Will Vicent Still I can't find any problems
models.py
from django.db import models
# Create your models here.
class Post(models.Model):
title = models.CharField(max_length=200)
author = models.ForeignKey(
'auth.User',
on_delete=models.CASCADE,
)
body = models.TextField()
def __str__(self):
return self.title
views.py
from django.views.generic import ListView, DetailView # new
from .models import Post
# Create your views here.
class BlogListView(ListView):
model = Post
template_name = 'home.html'
class BlogDetailView(DetailView): # new
Model = Post
template_name = 'post_detail.html'
urls.py
# blog/urls.py
from django.urls import path
from .views import BlogListView, BlogDetailView # new
urlpatterns = [
path('post/<int:pk>/', BlogDetailView.as_view(), name='post_detail'), # new
path('', BlogListView.as_view(), name='home'),
]
post_detail.html
<!-- templates/post_detail.html-->
{% extends 'base.html' %}
{% block content %}
<div class="post-entry">
<h2>{{ post.title }}</h2>
<p>{{ post.body }}</p>
</div>
{% endblock content %}
This code is supposed to allow me to see my posts when I browse to http://127.0.0.1/posts/1 or post/2
You have a simple typo in your DetailView: Model instead of model.
Related
I'm sorry to ask something simple, but i'm just trying to add forms into my Django project
I'm just following this tutorial on forms, from:
https://www.youtube.com/watch?v=6oOHlcHkX2U&t=115s
Here's my form in HTML
<div class="form-popup" id="myForm">
<form class="form-container" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="add">
<button type="button" class="btn cancel" onclick="closeForm()">Close</button>
</form>
</div>
Here's my code in forms.py:
from django import forms
from .models import Stream
class CameraForm(forms.ModelForm):
class Meta:
model = Stream
fields = (
'name',
'RTSP',
)
my views.py
from django.shortcuts import render, get_object_or_404
from CGI.models import tank_system, ambient, Limit
from CGI.basicfun import selectDates, weekSelect
import logging
logger = logging.getLogger(__name__)
from .forms import CameraForm
def index(request):
forms = CameraForm(request.POST or None)
if forms.is_valid():
forms.save()
tank = tank_system.objects.latest('datetime')
room = ambient.objects.latest('datetime')
limit, created = (Limit.objects.get_or_create())
return render(request, 'CGI/Pages/DashBoard.html', {'tank':tank,'room':room, 'limit':limit, 'form':forms})
Here my Models:
from django.db import models
from django.utils import timezone
class tank_system(models.Model):
... #my tank tables
class ambient (models.Model):
... #my room tables
class Limit (models.Model):
... #my limit tables
# here the class that use in the forms
class Stream (models.Model):
name = models.CharField(max_length=30)
RTSP = models.CharField(max_length=200)
My apps URL
urlpatterns = [
path(r'',login_required(views.index), name='index'),
path(r'^Water-data-chart/',login_required(views.Lquid), name='tank'),
path(r'^Ambient-data-chart/',login_required(views.Ambient), name='room'),
path(r'Rest-api/', include(router.urls))
]
My project URL
urlpatterns = [
path(r'admin/', admin.site.urls),
path(r'accounts/', include('django.contrib.auth.urls')),
path(r'api-auth/', include('rest_framework.urls'), name='rest_framework'),
path(r'', include('CGI.urls')),
]
Now problems is {{from.as_p}} is supposed to create an html text box form me input and post which ever data,
(here how its support to look: )
but when I open up local test, I see nothing,
Here What I see:
leaving me stumped and confused.
I really appreciate if you could help.
I want to show the details of a product added.
I followed this link and i could create an add product page
https://simpleisbetterthancomplex.com/tutorial/2018/01/29/how-to-implement-dependent-or-chained-dropdown-list-with-django.html
once the product is added, i want to show the details of the product added in a new page.
So i tried the following:
class ProductDetailView(DetailView):
model = Product
context_object_name = 'product'
queryset = Product.objects.filter(pk)
I really don't know what to put in the filter, or using filter is correct. i had tried using latest and order by instead of filter but they did not work.
my urls.py is as follows:
urlpatterns = [
path('', views.ProductDetailView.as_view(), name='product_changelist'),
#path('', views.ProductListView.as_view(), name='product_changelist'),
path('add/', views.ProductCreateView.as_view(), name='product_add'),
path('<int:pk>/', views.ProductUpdateView.as_view(), name='product_change'),
path('ajax/load-subcategory/', views.load_subcategory, name='ajax_load_subcategory'),
#path('<int:product_id>', views.detail, name='detail'),
]
Currently i am getting error as
AttributeError at /product/
Generic detail view ProductDetailView must be called with either an object pk or a slug.
I read that we have to provide the pk in urls.py so i tried providing pk as follows:
path('<int:pk>', views.ProductDetailView.as_view(), name='product_changelist'),
but then i get an error as follows:
NoReverseMatch at /product/add/
Reverse for 'product_changelist' with no arguments not found. 1 pattern(s) tried: ['product\\/(?P<pk>[0-9]+)$']
Any help in solving this problem is highly appreciated. I am new to django so may have done many mistakes above.
Edit 1:
I tried the suggestion given by #Radico, but still the same error: What i did is as follows:
Changed my ProductDetailView as follows:
class ProductDetailView(DetailView):
model = Product
context_object_name = 'product'
the product_list.html now has the following content
{% extends 'base.html' %}
{% block content %}
<br />
<br />
<br />
<br />
<br />
This is the page getting displayed121
{% url 'product_changelist' pk=object.pk %}
{% endblock %}
Still i get the same error as
AttributeError at /product/
Generic detail view ProductDetailView must be called with either an object pk or a slug
I did not change anything in urls.py.... do i have to change anything in it as well?
Edit 2:
Here is my urls.py
from django.urls import include, path
from . import views
urlpatterns = [
path('<int:pk>', views.ProductDetailView.as_view(), name='product_changelist'),
#path('', views.ProductDetailView.as_view(), name='product_changelist'),
#path('', views.ProductListView.as_view(), name='product_changelist'),
path('add/', views.ProductCreateView.as_view(), name='product_add'),
path('', views.ProductUpdateView.as_view(), name='product_change'),
path('ajax/load-subcategory/', views.load_subcategory, name='ajax_load_subcategory'),
#path('<int:product_id>', views.detail, name='detail'),
]
My views.py is as follows:
from django.shortcuts import render
from django.urls import reverse_lazy
from django.views.generic import CreateView, UpdateView, ListView, DetailView
from category.models import Subcategory
from product.forms import ProductForm
from product.models import Product
class ProductListView(ListView):
model = Product
context_object_name = 'product'
queryset = Product.objects.filter()
class ProductDetailView(DetailView):
model = Product
context_object_name = 'product'
# queryset = Product.objects.filter()
# class ProductDetailView(DetailView):
# template_name = 'product/product_list.html'
# #model = User
# #context_object_name = 'foo'
#
# def get_object(self):
# #return get_object_or_404(Product, pk=request.session['product_id'])
# return get_object_or_404(Product, pk=self.request.
class ProductCreateView(CreateView):
model = Product
form_class = ProductForm
success_url = reverse_lazy('product_changelist')
def productlist(request, product_id):
product = Product.objects.get(productid=product_id)
return render(request, 'product/product_list.html', {'product': product})
# def productlist(request):
# prodlist = Product.objects.order_by('-pk')[0]
# return render(request, 'product/product_list.html', {'prodlist': prodlist})
class ProductUpdateView(UpdateView):
model = Product
form_class = ProductForm
success_url = reverse_lazy('product_changelist')
def load_subcategory(request):
category_id = request.GET.get('category')
subcategory = Subcategory.objects.filter(category_id=category_id).order_by('name')
return render(request, 'product/subcategory_dropdown_list_options.html', {'subcategory': subcategory})
My product_list.html is as i had pasted earlier
{% extends 'base.html' %}
{% block content %}
<br />
<br />
<br />
<br /><br />
This is the page getting displayed121
{% url 'product_changelist' pk=object.pk %}
{% endblock %}
First: You don't need to get query set within the detailview the object is already available, you can call it in the template object or class name lowercase in your case product.
Second: make sure that you pass pk in urls refer to the detailview within templates i.e {% url 'product_change' pk=object.pk %}
I believe you got the error for second part check the url in product_changelist template and you may forgot to pass pk=object.pk
If you want to use Regular expressions when you're using path:
from django.urls import path , re_path
re_path(r'^product/(?P<pk>\d+)$', views.ProductUpdateView.as_view(), name='product_change'),
My goal is to list a few links in a page and I was wondering if there's a better way of do this line of code:
<a href={% url ''|add:app_name|add:':'|add:model_name|add:post_fix %}> {{ model_name }} </a>
This part : ''|add:app_name|add:':'|add:model_name|add:post_fix
-- If so, what is the flaw in my thinking, is it the URL-name, or doing too much in the template, or something else? Should I do the construction in python code in view.py, if so can you show me how you would tackle this problem?
a_template.html
{% for model_name in list_model_names%}
....
<a href={% url ''|add:app_name|add:':'|add:model_name|add:post_fix %}> {{ model_name }} </a>
....
{% endfor %}
url.py
from django.conf.urls import url
from . import views
app_name = 'app'
urlpatterns = [
url(r'^stone/$, view.....as_view(), name='stone_index'),
url(r'^cloud/$', view.....as_view(), name='cloud_index'),
]
views.py
from django.shortcuts import render_to_response
from django.views import View
from app.models import (Stone, Cloud)
class ThisView(View):
template_name = 'app/a_template.html'
models = [Stone, Cloud]
model_names = [model._meta.model_name for model in models]
app_name = 'app'
post_fix = '_index'
dict_to_template = {'app_name': app_name,
'list_model_name': model_names,
'post_fix': post_fix}
def get(self, *args, **kwargs):
return render_to_response(self.template_name, self.dict_to_template)
Thank you for your time.
It would be tidier to reverse the urls in the template
from django.urls import reverse . # Django 1.9+
# from django.core.urlresolvers import reverse # Django < 1.9
model_names = [model._meta.model_name for model in models]
app_name = 'app'
post_fix = '_index'
urls = [reverse('%s:%s%s' % (app_name, model, post_fix)) for model in model_names
Then zip the model names and urls together and include them in the template context:
models_and_urls = zip(model_names, urls)
dict_to_template = {'models_and_urls: models_and_urls}
You can then loop through the model names and urls in your template.
{% for model_name, url in models_and_urls %}
....
{{ model_name }}
....
{% endfor %}
I am trying to create a table view with pagination, sorting, and filtering, using the most common/standard/recommended approach for Django 1.6. This seems to be Generic Class-Based Views and django-tables2. I've found at least two different examples of how to add filtering, one with django-filters and crispy-forms and the other with django_filters, but neither includes a complete working example. When I follow either approach, I get stuck filling in the missing material. Using the crispy approach from Nicolas Kuttler, I have:
models.py
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=100)
tables.py
import django_tables2 as dt2
from .models import Author
class AuthorTable(dt2.Table):
class Meta:
model = Author
If I understand correctly, PagedFilteredTableView is a generic class from which I then subclass AuthorView, as opposed to the other example, in which FilteredSingleTableView is, I think, supposed to be understood as something like, if Author was the table, AuthorFilteredSingleTableView.
views.py
from .tables import AuthorTable
from .models import Author
from django_tables2 import SingleTableView
class PagedFilteredTableView(SingleTableView):
"""
Generic class from http://kuttler.eu/post/using-django-tables2-filters-crispy-forms-together/
which should probably be in a utility file
"""
filter_class = None
formhelper_class = None
context_filter_name = 'filter'
def get_queryset(self, **kwargs):
qs = super(PagedFilteredTableView, self).get_queryset()
self.filter = self.filter_class(self.request.GET, queryset=qs)
self.filter.form.helper = self.formhelper_class()
return self.filter.qs
def get_table(self, **kwargs):
table = super(PagedFilteredTableView, self).get_table()
RequestConfig(self.request, paginate={'page': self.kwargs['page'],
"per_page": self.paginate_by}).configure(table)
return table
def get_context_data(self, **kwargs):
context = super(PagedFilteredTableView, self).get_context_data()
context[self.context_filter_name] = self.filter
return context
class AuthorTableView(PagedFilteredTableView):
model = Author
table_class = AuthorTable
paginate_by = 30
filter_class = AuthorFilter
formhelper_class = AuthorFilterFormHelper
This is, aside from the template, all of the example code from the source, and manage.py is complaining that AuthorFilter isn't defined, so I guess that goes into ... maybe filters.py?
filters.py
import django_filters as df
from .models import Author
class AuthorFilter(df.FilterSet):
class Meta:
model = Author
And, back in views.py, from .filters import AuthorFilter.
And now AuthorFilterFormHelper isn't defined, and it's not clear if that's something I should explicitly define (how?), as implied by the line formhelper_class = FooFilterFormHelper, or if that should actually be done automatically somehow, as implied by self.filter.form.helper = self.formhelper_class(). And we still haven't gotten to urls.py or the template. Please help fill in the blanks, or indicate a better path to go down to add filtering to a generic class-based view.
With trial and error and some suggestions from Nicolas Kuttler, I was able to get his example working. I butchered a little bit of his example but this does seem to be close to the least amount of code necessary in Django to have a generic class-based list view page with sorting, filtering (and thus search), and pagination, and I don't think it violates (too m)any Django coding practices. Here is all of the code required:
models.py (no changes from the question)
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=100)
And a slight change to the tables.py in the question:
import django_tables2 as dt2
from .models import Author
class AuthorTable(dt2.Table):
class Meta:
model = Author
attrs = {"class": "paleblue"}
per_page = 30
filters.py (no changes from the question)
import django_filters as df
from .models import Author
class AuthorFilter(df.FilterSet):
class Meta:
model = Author
forms.py. I couldn't figure out how/where to get the form submit button out of django_filters in combination with everything else, so this code suppresses the form wrapper tags from crispy, and then we provide that HTML in the template, which is probably the kludgiest part of this.
from django import forms
from .models import Author
from crispy_forms.helper import FormHelper
class AuthorListFormHelper(FormHelper):
model = Author
form_tag = False
I moved the helper function out of views.py to a separate file and had to remove the pagination code to prevent an error (though pagination still works). So,
utils.py
from django_tables2 import SingleTableView
from django_tables2.config import RequestConfig
class PagedFilteredTableView(SingleTableView):
filter_class = None
formhelper_class = None
context_filter_name = 'filter'
def get_queryset(self, **kwargs):
qs = super(PagedFilteredTableView, self).get_queryset()
self.filter = self.filter_class(self.request.GET, queryset=qs)
self.filter.form.helper = self.formhelper_class()
return self.filter.qs
def get_context_data(self, **kwargs):
context = super(PagedFilteredTableView, self).get_context_data()
context[self.context_filter_name] = self.filter
return context
Instead of the views.py in the question, this views.py:
from .models import Author
from .tables import AuthorTable
from .filters import AuthorListFilter
from .forms import AuthorListFormHelper
from utils import PagedFilteredTableView
class AuthorList(PagedFilteredTableView):
model = Author
table_class = AuthorTable
filter_class = AuthorListFilter
formhelper_class = AuthorListFormHelper
And this template:
author_list.html (the name is not explicitly specified anywhere because it's implied by the model in the view, I think)
{% extends "base.html" %}
{% load render_table from django_tables2 %}
{% load crispy_forms_tags %}
{% block content %}
{% render_table table %}
<hr/>
<form action="" method="get">
{% crispy filter.form filter.form.helper %}
<input type="submit" value="Filter"/>
</form>
{% endblock content %}
And, for completeness, a line in urls.py:
...
url(r'^$', views.AuthorTableList.as_view(), name='author_table'),
...
And you must have the packages django-tables2, django-filters, and crispy-forms installed and configured as per their instructions. The one thing that tripped me up was that I somehow, on the first attempt, missed that I needed this in settings.py:
CRISPY_TEMPLATE_PACK = 'bootstrap'
All of this is for Django 1.6.
Your answer help me, so i edited your code to include the submit button from crispy-forms
forms.py. I couldn't figure out how/where to get the form submit button out of django_filters in combination with everything else, so this code suppresses the form wrapper tags from crispy, and then we provide that HTML in the template, which is probably the kludgiest part of this.
forms.py (UPDATED)
from django import forms
from .models import Author
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, ButtonHolder, Submit
class AuthorListFormHelper(FormHelper):
model = Author
form_tag = False
# Adding a Filter Button
layout = Layout('name', ButtonHolder(
Submit('submit', 'Filter', css_class='button white right')
))
author-list.html (UPDATED)
{% extends "base.html" %}
{% load render_table from django_tables2 %}
{% load crispy_forms_tags %}
{% block content %}
{% render_table table %}
<hr/>
<form action="" method="get">
{% crispy filter.form filter.form.helper %}
</form>
{% endblock content %}
I am fairly new to CBV and am trying to make sense of it. I copied the following example from the django doc page:
https://docs.djangoproject.com/en/dev/topics/class-based-views/generic-editing/
models.py
from django.core.urlresolvers import reverse
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=200)
def get_absolute_url(self):
return reverse('author-detail', kwargs={'pk': self.pk})
views.py
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.core.urlresolvers import reverse_lazy
from myapp.models import Author
class AuthorCreate(CreateView):
model = Author
fields = ['name']
class AuthorUpdate(UpdateView):
model = Author
fields = ['name']
class AuthorDelete(DeleteView):
model = Author
success_url = reverse_lazy('author-list')
urls.py
from django.conf.urls import patterns, url
from myapp.views import AuthorCreate, AuthorUpdate, AuthorDelete
urlpatterns = patterns('',
# ...
url(r'author/add/$', AuthorCreate.as_view(), name='author_add'),
url(r'author/(?P<pk>\d+)/$', AuthorUpdate.as_view(), name='author_update'),
url(r'author/(?P<pk>\d+)/delete/$', AuthorDelete.as_view(), name='author_delete'),
)
At author/add/ I indeed get the form, but when I enter the string I get the following error:
Reverse for 'author-detail' with arguments '()' and keyword arguments '{'pk': 3}' not found.
It seems like the new entry has been added to the database, but it could not resolve the URL for the next view?
So I am puzzled, what is this get_absolute_url() object's method supposed to do, how does it work (I could not grasp it from the django doc) and how do I fix the issue?
Thanks.
EDIT 1: added the template:
author_form.html:
<form action="" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Create" />
</form>
By default, when a new model is created django will redirect you to a models absolute url as returned by the get_absolute_url method. In your example you would need to add a url with the name author-detail that accepts a pk keyword argument.
urlpatterns = patterns('',
# ...
url(r'author/(?P<pk>\d+)/$', AuthorDetail.as_view(), name='author-detail'),
)
Note the name of the url matches the name of the view in the get_absolute_url method.
Use it in your templates:
{% for author in authors %}
{{author.name}}
{% endfor %}