I want to turn a function view into a class-based view.
Here is the View & URL path that I have right now.
View:
def customer(request, pk):
customer = Customer.objects.get(id=pk)
return render(request, 'accounts/customer.html)
URL Path:
path('customer/<str:pk>/, views.customer, name='customer')
What would the proper syntax be to turn this view into a class-based view.
I am mainly curious about how to access the primary key here using a class-based view.
Thanks!
You can use Detail View.
in your views.py
from django.views.generic.detail import DetailView
from .models import Customer
class CustomerDetails(DetailView):
model = Customer
template_name = 'customerdetail.html' #deafaults to customer_detail.html
in urls.py
path('customer/<int:pk>', views.CustomerDetails.as_view(), name='customer')
the context that will be passed to customerdetail.html template will have the default name 'object'. access the fields of customer instance by {{object.<field_name>}}.
You can override the attributes and methods of DetailView.
for moreinfo : DetailView
If you want more control in your view you can use generic View
from django.views.generic.detail import View
from .models import Customer
class CustomerDetails(View):
def get(self, *args, **kwargs):
customer = Customer.objects.get(id=kwargs['pk'])
return render(self.request, 'accounts/customer.html)
urls.py
path('customer/<int:pk>', views.CustomerDetails.as_view(), name='customer')
arguments found in the url are stored in **kwargs
Related
The LoginRequiredMixin is not working as intended for the class based view below, I was able to access the webpage regardless of login status, but it should have redirected the unauthorized users to the login page. Where have I gone wrong?
from django.shortcuts import render, redirect
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import FormView
from .forms import UpdatePortfolio
# Create your views here.
class UpdatePortfolioView(LoginRequiredMixin, FormView):
login_url = 'users:login'
redirect_field_name = 'mainpage:update'
form = UpdatePortfolio
template_name = 'mainpage/updateportfolio.html'
def get_object(self):
# return self.request.user.id
return self.request.user.pk
def get(self, request, *args, **kwargs):
form = self.form_class
return render(request, self.template_name, {'form': form})
I think the Problem is Because you Override the Get method... Because the functionality of Redirecting the users will add to the get function and you had overridden it
remove it ... and you should know that all the code in the function is already will be done by the FormView You don't have to write it
Read this Docs
I have created detailed views for the posts in my Django-based blog using the DetailView generic class and everything works fine so far. The problem, however, is that I have a field in my post model that is used to set the status of the posts (active, inactive, blocked) and I only want to render the detailed views when the status is active. If anyone knows of a way to achieve this, please let me know and I ask that you be as detailed as possible.
views.py
from .models import Post
from django.views.generic import DetailView
class PostDetailView(DetailView):
model = Post
context_object_name = 'post'
template_name = 'blog/post-detail.html'
def get_context_data(self, **kwargs):
context = super(PostDetailView, self).get_context_data(**kwargs)
context['title'] = Post.objects.filter(slug=self.object.slug).first()
return context
In your DetailView you can filter the queryset, for example you can filter with:
from django.views.generic import DetailView
class PostDetailView(DetailView):
queryset = Post.objects.filter(active=True)
# …
The DetailView will retrieve the element based on the primary key and/or slug on the queryset, so if the element is not in the filtered queryset, then you will retrieve a 404 error.
Here we assume that the Post model has an active field:
class Post(models.Model):
# …
active = models.BooleanField()
# …
Given the field and values are different, you should of course filter the queryset accordingly.
I want create a templateview but need to use a editable template on-the-fly, to this i can set a template from a code stored inside a field from a table.
# some_app/views.py
from django.views.generic import TemplateView
class AboutView(TemplateView):
template_name = "about.html" -> from table.field
Some ideia?
Great #WillemVanOnsem nice solution. But to complicate more, if i want to do in Django Rest like:
class FormularioDisplayView(APIView):
renderer_classes = [TemplateHTMLRenderer]
def get(self, request, pk):
formulario = get_object_or_404(Formulario, codigo=pk)
serializer = FormularioDisplaySerializer()
template_data = TemplateData.objects.get(name='model_01')
return Response({'serializer': serializer, 'formulario': formulario}) -> Render using template_data.template as the template
We can alter the TemplateView to obtain the content of a template from the database. For example we can have a model like:
# app/models.py
class TemplateData(models.Model):
name = models.CharField(max_length=128, unique=True)
template = models.CharField(max_length=32768)
Here the TemplateData model thus associates a name with the content of a template.
Next we can implement a TemplateFromDatabaseView where we override the render_to_response method [Django-doc]:
# app/views.py
from app.models import TemplateData
from django.http import HttpResponse
from django.views.generic import TemplateView
from django.template import Template, Context
class TemplateFromDatabaseView(TemplateView):
def render_to_response(self, context, **response_kwargs):
template_data = TemplateData.objects.get(name=self.template_name)
return HttpResponse(
Template(template_data.template).render(
RequestContext(self.request, context)
)
), **response_kwargs)
Then you can subclass it, for example with:
# app/views.py
# …
class AboutView(TemplateFromDatabaseView):
template_name = 'database_template_name'
Of course that means you need to add a TemplateData object to the database with as name the 'database_template_name' and with as template field, the content you want to render.
I want to add data to my database from form (which is CreateView). Unfortunately after posting I got
'ImproperlyConfigured at/persons/new/'
I was trying to edit my urls.py, but I think I missed something.
My views.py
class PersonListView(ListView):
model = Person
template_name = 'app/home.html'
context_object_name = 'users'
class PersonCreateView(CreateView):
model = Person
fields = ['name','surname']
My urls.py in project
*imports*
urlpatterns = [
path('admin/',admin.site.urls),
path('persons/', include('app.urls')),
]
My urls.py in app
*imports*
urlpatterns = [
path('',PersonListView.as_view(),name='persons),
path('new/',PersonCreateView.as_view(),name='person-create),
]
After submit my form, data are added to database but I got error like above.
Short answer: you should specify a success_url [Django-doc] attribute in your view, or override form_valid [Django-doc].
In a CreateView [Django-doc] (well most views with a FormMixin [Django-doc]), you need to specify what needs to happen when the form has been processed succesfully.
By default a ModelFormMixin [Django-doc] will first save the object [GitHub]:
def form_valid(self, form):
"""If the form is valid, save the associated model."""
self.object = form.save()
return super().form_valid(form)
and then the underlying FormMixin will redirect to the success_url [GitHub]:
def form_valid(self, form):
"""If the form is valid, redirect to the supplied URL."""
return HttpResponseRedirect(self.get_success_url())
The get_success_url will retrieve the success_url attribute [GitHub], and raise, as you noticed, an ImproperlyConfigured error if that one is missing:
def get_success_url(self):
"""Return the URL to redirect to after processing a valid form."""
if not self.success_url:
raise ImproperlyConfigured("No URL to redirect to. Provide a success_url.")
return str(self.success_url) # success_url may be lazy
In you view, you thus can specify a success_url, for example with reverse_lazy [Django-doc]:
from django.urls import reverse_lazy
class PersonCreateView(CreateView):
model = Person
fields = ['name','surname']
success_url = reverse_lazy('persons')
Here persons is the name of the path(..) to which we redirect. Redirecting is typically the preferred way to handle a successful form: it is part of the Post/Redirect/Get architectural pattern [wiki]. If you would render a page for the POST request, then a user that refreshes the page on the browser, will resend the same data to the server, and thus might actually create a second object.
Another option is to override form_valid, and do something else after calling the super().form_valid(form) (since that will save the object to the database).
I am using Generic Class based views for my Project like:
ListView (Queryset returning all the objects)
DetailView (Queryset for single object)
CreateView (Foreignkey data in select boxes)
UpdateView (Foreignkey data in select boxes)
How to write a generic Mixin for CBV so that the queryset returns only the data owned by the logged in user.
Just add get_queryset method and loginrequiredmixed like:
from django.contrib.auth.mixins import LoginRequiredMixin
class ArticleListView(ListView, LoginRequiredMixin):
model = Article
def get_queryset(self):
return Article.objects.filter(publisher=self.request.user) #Just and example, fit it to your problem