I'm using Django 2.0
I have two modesl course and chapter
I want to pass course.pk in CreateView of chapter since chapter is related to course.
This is my urls.py
from django.urls import path
from courses.views import Courses, NewCourse, CourseView, NewChapter
app_name = 'course'
urlpatterns = [
path('all', Courses.as_view(), name='list'),
path('new', NewCourse.as_view(), name='new'),
path('<pk>/detail', CourseView.as_view(), name='detail'),
path('<course_id>/chapter/add', NewChapter.as_view(), name='new_chapter')
]
and NewChapter(CreateView)
class NewChapter(CreateView):
template_name = 'courses/chapter/new_chapter.html'
model = Chapter
fields = ['name']
def get_context_data(self, **kwargs):
context = super(NewChapter, self).get_context_data(**kwargs)
course = Course.objects.get(pk=kwargs['course_id'])
if course is None:
messages.error(self.request, 'Course not found')
return reverse('course:list')
return context
def form_valid(self, form):
form.instance.created_by = self.request.user
form.instance.course = Course.objects.get(pk=self.kwargs['course_id'])
form.save()
I also want to carry on validation if the Course with passed course_id exists or not. If it does not exists user will be redirected back otherwise he will be able to add chapter to it.
But it is giving error as
KeyError at /course/9080565f-76f4-480a-9446-10f88d1bdc8d/chapter/add
'course_id'
How to access parameters of path url in view?
You need to use self.kwargs, not kwargs.
course = Course.objects.get(pk=self.kwargs['course_id'])
Related
I am creating a simple application, successfully created for a single user, but I want to develop for multiple users, but unable to do so... i.e. user A can create his task and save in the database. similar B user can create tasks and store in the database. and each can see their own tasks I am newbie unable to proceed with the creation of instance can someone please guide me or point me to a blog ( searched online but no help ) I already asked this question however i was not clear ( django each user needs to create and view data Issue) hope now I am clear.
My model :
from django.contrib.auth.models import User, AbstractUser
from django.db import models
# Create your models here.
from django.db.models import Sum, Avg
class Task(models.Model):
user = models.ForeignKey(User, null=True,on_delete=models.CASCADE)
title = models.CharField(max_length=200)
complete = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True,auto_now=False,blank=True)
purchase_date = models.DateField(auto_now_add=False,auto_now=False,blank=True,null=True)
price = models.FloatField(max_length=5,default='0.00',editable=True)
def __str__(self):
return self.title
#classmethod
def get_price_total(cls):
total = cls.objects.aggregate(total=Sum("price"))['total']
print(total)
return total
Views
def createTask(request):
form = TaskForm()
if request.method =='POST':
form=TaskForm(request.POST)
if form.is_valid():
form.save()
return redirect('query')
context = {'form':form}
return render(request,'tasks/create.html',context)
def display(request):
# tasks = Task.objects.all()
tasks = request.user.task_set.all()
form = TaskForm()
if request.method =='POST':
if form.is_valid():
form.save()
return redirect('/')
# tasks= task.objects.all()
print("tasks",Task.get_price_total)
context = {'tasks':tasks,'form':form,'Totalprice':Task.get_price_total}
return render(request,'tasks/products.html',context)
urls
from django.urls import path
from . import views
urlpatterns = [
#path('', views.index, name="list"),
path('', views.query, name="query"),
path('create/', views.createTask, name="create"),
path('update_task/<str:pk>/', views.updateTask, name="update_task"),
path('register/', views.registerPage,name="register"),
path('login/', views.loginPage,name="login"),
path('logout/', views.logoutUser,name="logout"),
path('delete/<str:pk>/', views.deleteTask, name="delete"),
path('query/', views.query, name="query"),
path('products/', views.display, name="products"),
path('search/', views.showresults, name="search"),
]
Error (output)
Internal Server Error: /products/
Traceback (most recent call last):
File "C:\Users\s5114509\AppData\Local\Programs\Python\Python38\lib\site-packages\django\core\handlers\exception.py", line 34, in inner
response = get_response(request)
File "C:\Users\s5114509\AppData\Local\Programs\Python\Python38\lib\site-packages\django\core\handlers\base.py", line 124, in _get_response
raise ValueError(
ValueError: The view tasks.views.display didn't return an HttpResponse object. It returned None instead.
[21/Oct/2020 14:35:59] "GET /products/ HTTP/1.1" 500 60680
From what I heard it sounds lke you want to save a task when a user creates one. You don't want to include the user field in the form. You have to first get the model instance returned by the TaskForm.save() method. Now you have to assign the user field to the request.user since the user is authenticated. Here is how you can achieve that.
def createTask(request):
form = TaskForm()
task = None
if request.method =='POST':
form=TaskForm(request.POST)
if form.is_valid():
#Just get the Task instance do not make any commitments to database
task = form.save(commit=False)
#Now update the user
task.user = request.user
#Finally save to database
task.save()
return redirect('query')
context = {'form':form}
return render(request,'tasks/create.html',context)
On display you are getting an error because you are return a response only when a POST request is made. Check you identation and correct it. Identation mean scope in python. Check I have modified you code
def display(request):
#tasks = Task.objects.all()
tasks = request.user.task_set.all()
form = TaskForm()
if request.method =='POST':
if form.is_valid():
form.save()
return redirect('/')
#tasks= task.objects.all()
print("tasks",Task.get_price_total)
context = {'tasks':tasks,'form':form,'Totalprice':Task.get_price_total}
return render(request,'tasks/products.html',context)
Take a look at python identation
I was previously using Django==2.0.6 now I want to upgrade it to Django==2.2.3. And Doing some research I get to know that In django-2.1, the old function-based views of login, logout have been removed.
I still want to add some extra context to LoginView as per my project requirement..
Previously using Function Based View I have done the following:
from django.contrib.auth.views import login as auth_views_login
def login(*args, **kwargs):
"""
Auth Login View
"""
ecom_company = Ecom_Company.objects.filter(pk=1).first()
landing_details = Landing.objects.filter(company=ecom_company).first()
category_list = Categories.objects.filter(
company=ecom_company).exclude(name__exact='Lab Test').order_by('id')
partners_list = Partners.objects.filter(
company=ecom_company).order_by('-id')
stock_list = StockItem.objects.filter(
organisation=ecom_company.organisation).order_by('id')
context = {
'ecom_company': ecom_company,
'landing_details': landing_details,
'category_list': category_list,
'partners_list': partners_list,
'stock_list': stock_list
}
return auth_views_login(*args, extra_context=context, **kwargs)
And in urls:
url(r'login/$', views.login,
{'template_name': 'login.html'}, name="login"),
How do I pass the extra context for Class Based Login View as because Django==2.2 does not support the above.
I think you can use the LoginView like this:
from django.contrib.auth import views as auth_views
class MyLoginView(auth_views.LoginView):
template_name = 'login.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
ecom_company = Ecom_Company.objects.filter(pk=1).first()
landing_details = Landing.objects.filter(company=ecom_company).first()
category_list = Categories.objects.filter(
company=ecom_company).exclude(name__exact='Lab Test').order_by('id')
partners_list = Partners.objects.filter(
company=ecom_company).order_by('-id')
stock_list = StockItem.objects.filter(
organisation=ecom_company.organisation).order_by('id')
context.update({
'ecom_company': ecom_company,
'landing_details': landing_details,
'category_list': category_list,
'partners_list': partners_list,
'stock_list': stock_list
}
return context
# url
url(r'login/$', views.MyLoginView.as_view(), name="login"),
I have a class based view which needs to accept a Form submission. I am trying to auto-populate some of the form fields using the primary key within the URL path (e.g. /main/video/play/135). The class based view is based on FormView, the code I have makes the pk available in context if I use TemplateView, but that is not particularly good for handling forms.
urls.py
app_name = 'main'
urlpatterns = [
#path('', views.index, name='index'),
path('video/<int:pk>', views.VideoDetailView.as_view(), name='detail'),
path('video/preview/<int:pk>', views.VideoPreview.as_view(), name='preview'),
path('player', views.PlayerListView.as_view(), name='player_list'),
path('video/play/<int:pk>/', views.VideoPlayView.as_view(), name='play'),
path('', views.VideoListView.as_view(), name="video_list")
]
Relevant class from views.py:
class VideoPlayView(FormView):
template_name = "main/video_play.html"
form_class = VideoPlayForm
initial = {}
http_method_names = ['get', 'post']
def get_initial(self, **kwargs):
initial = super().get_initial()
#initial['video'] = pk
initial['watch_date'] = datetime.date.today()
return initial
def get_context_data(self, **kwargs):
kc = kwargs.copy()
context = super().get_context_data(**kwargs)
video = Video.objects.get(context['pk'])
context['video'] = video
context['test'] = kc
self.initial['video'] = video.pk
context['viewers'] = Viewer.objects.all()
context['players'] = Player.objects.filter(ready=True)
return context
def form_valid(self, form):
return HttpResponse("Done")
I get a key error at the line:
video = Video.objects.get(context['pk'])
Viewing the debug info on the error page indicates that the context does not have the pk value stored within it.
If I change the base class to TemplateView with a FormMixin I don't get this key error (but I do have problems POSTing the form data), so I know that the code is basically okay. My understanding is that the FormView class should populate context in the same way as the TemplateView class.
Any idea why FormView behaves this way, and how can I get this working?
If you want pk from the URL, self.kwargs['pk'] will work in all Django generic class-based-views.
In TemplateView, the get() method passes kwargs to the get_context_data method, so you can use context['pk']. The FormView get() method calls get_context_data() without passing any kwargs, so that won't work.
I'm using Django-registration-redux and I want give more data to a view to render my base template. I read the example in doc.
My url.py:
class MyPasswordChangeView(PasswordChangeView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# context['book_list'] = Book.objects.all() # example in doc
context_dict = services.get_base_data_for_views(request)
return context_dict
urlpatterns = [
...
path('accounts/password/change/', MyPasswordChangeView.as_view(
success_url=reverse_lazy('auth_password_change_done')), name='auth_password_change'),
...
]
I have the extra data in services.py but this code gives error:
name 'request' is not defined
So context_dict isn't defined. Where can I take my request from? Mainly I need the user (but print(user)= 'user' is not defined). Or should I write another function?
In methods of Django class based views, you can access the request with self.request.
class MyPasswordChangeView(PasswordChangeView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context_dict = services.get_base_data_for_views(self.request)
return context_dict
Therefore you can access the user with self.request.user. Normally you would want to use login_required or LoginRequiredMixin so that only logged-in users can access the view, but in your case PasswordChangeView takes care of that for you.
Currenly I can get a gallery of currently logged in user via any urls as
example.com/user/gallery
example.com/user123/gallery
example.com/312any-thing/gallery
This is not what I want. What I want is to check first, if user exists, and then provide required gallery via ArchiveIndexView.
How can I get the username part of example.com/username/gallery in ArchiveIndexView class in order to implement
user = get_object_or_404(UserProfile, slug=username)
?
# project urls
urlpatterns = [
url(r'^(?P<slug>[\w.-]+)/', include('profiles.urls', namespace='profiles_user')),
]
# app.urls
urlpatterns = [
url(r'^$', views.ProfileDetailView.as_view(), name='profiles_home'),
url(r'^gallery/$', views.ProfileGalleryArchiveIndexView.as_view(), name='profiles_gallery'),
]
# app.views
class ProfileGalleryDateView(object):
date_field = 'date_added'
allow_empty = True
class ProfileGalleryArchiveIndexView(ProfileGalleryDateView, ArchiveIndexView):
def get_queryset(self):
user = self.request.user # here I want to get username from url
user = get_object_or_404(UserProfile, slug=username)
return Gallery.objects.filter(galleryextended__user=user).is_public()
I tried to get username from url using:
def get_context_data(self, **kwargs):
context = super(ProfileDetailView, self).get_context_data(**kwargs)
user = get_object_or_404(UserProfile, pk=kwargs['object'].pk)
but get_queryset executes earlier than get_context_data.
Your URL captures the username as slug, so you can get it from self.kwargs['slug'].