I've been attempting to construct a multi-step form using the Django session wizard for hours, but I keep getting the error, AttributeError: 'function' object has no property 'as_view'. I'm not sure why this mistake occurred. Any ideas?
views
from django.shortcuts import render
from formtools.wizard.views import SessionWizardView
from .forms import WithdrawForm1, WithdrawForm2
class WithdrawWizard(SessionWizardView):
template_name = 'withdraw.html'
form_list = [WithdrawForm1, WithdrawForm2]
def done(self, form_list, **kwargs):
form_data = [form.cleaned_data for form in form_list]
return render(self.request, 'done.html', {'data': form_data})
forms
from django import forms
from .models import Investment, Withdraw
from .models import WithdrawStepOne, WithdrawStepTwo
class WithdrawForm1(forms.ModelForm):
class Meta:
model = WithdrawStepOne
fields = ['investment_id',]
class WithdrawForm2(forms.ModelForm):
class Meta:
model = WithdrawStepTwo
fields = [
'proof_of_address',
'user_pic'
]
urls
from django.urls import path
from .forms import WithdrawForm1, WithdrawForm2
from . import views
urlpatterns = [
path('withdraw/', views.WithdrawWizard.as_view(), name='withdraw'),
]
You used #login_required decorator on WithdrawWizard class, but the decorator works only for function based views.
Use LoginRequiredMixin for class based views.
Related
i can't call my detail class using reverse_lazy
from django.shortcuts import render, redirect
from django.urls import reverse_lazy, reverse
from . models import Task
from . forms import Taskform
from django.views.generic import ListView
from django.views.generic.detail import DetailView
from django.views.generic.edit import UpdateView
class Tasklistview(ListView):
model = Task
template_name = 'home.html'
context_object_name = 'task'
class Detailview(DetailView):
model=Task
template_name = "details.html"
context_object_name = 'task'
class Updateview(UpdateView):
model = Task
template_name = "update.html"
context_object_name = "task"
fields = ('name', 'priority', 'date')
def get_success_url(self):
return reverse_lazy("cbvdetail",kwargs={'pk':self.object.id})
urls.py
from django.urls import path
from . import views
app_name='todoapp'
urlpatterns = [
path('',views.home,name='home'),
# path('details', views.details,name='ere')
path('delete/<int:id>/',views.delete,name='delete'),
path('edit/<int:id>/',views.update,name='update'),
path('cbvhome/',views.Tasklistview.as_view(),name='home'),
path('cbvdetail/<int:pk>/',views.Detailview.as_view(),name='cbvdetail'),
path('cbvupdate/<int:pk>/',views.Updateview.as_view(),name='edit'),
]
i want to resolve this
You specified an app_name in the urls.py file. That means you need to prefix the name of the view with that app label, so:
def get_success_url(self):
return reverse_lazy('todoapp:cbvdetail', kwargs={'pk':self.object.id})
If you override get_success_url, it does not make much sense to work with reverse_lazy, since that method will (normally) only be triggered in case the urls are already loaded, you can thus work with:
from django.urls import reverse
# ⋮
def get_success_url(self):
return reverse('todoapp:cbvdetail', kwargs={'pk':self.object.id})
i am not able to run this code
viwes.py
from django.shortcuts import render, redirect
from django.urls import reverse_lazy, reverse
from . models import Task
from . forms import Taskform
from django.views.generic import ListView
from django.views.generic.detail import DetailView
from django.views.generic.edit import UpdateView,DeleteView
class Tasklistview(ListView):
model = Task
template_name = 'home.html'
context_object_name = 'task'
class Detailview(DetailView):
model=Task
template_name = "details.html"
context_object_name = 'task'
class Updateview(UpdateView):
model = Task
template_name = "update.html"
context_object_name = "task"
fields = ('name', 'priority', 'date')
def get_success_url(self):
return reverse_lazy('todoapp:cbvdetail',kwargs={'pk':self.object.id})
class Deleteview(DetailView):
model = Task
template_name = 'delete.html'
success_url = reverse_lazy('todoapp:home')
urls.py
from django.urls import path
from . import views
app_name='todoapp'
urlpatterns = [
path('',views.home,name='home'),
path('delete/<int:id>/',views.delete,name='delete'),
path('edit/<int:id>/',views.update,name='update'),
path('cbvhome/',views.Tasklistview.as_view(),name='home'),
path('cbvdetail/<int:pk>/',views.Detailview.as_view(),name='cbvdetail'),
path('cbvupdate/<int:pk>/',views.Updateview.as_view(),name='edit'),
]
when i run this code i am getting a error this page isn't working right now
i am not able to run this code
gngnitgbnugriujvnnvtvnviuvntnvtvitu
You are inheriting you Deleteview from a DetailView, not a DeleteView, hence the error:
from django.views.generic import DeleteView
class Deleteview(DeleteView):
model = Task
template_name = 'delete.html'
success_url = reverse_lazy('todoapp:home')
I would however strongly advise not to give your views names like Deleteview, since it is easy to confuse this with the Django builtin class-based views. Usually the model is specified in the name, so TaskDeleteView instead of Deleteview:
class TaskDeleteView(DeleteView):
model = Task
template_name = 'delete.html'
success_url = reverse_lazy('todoapp:home')
I'm currently making a simple get/post api with django 3. After i run the server and go to the employee/article/ url it return an error
VIEW.PY
from django.shortcuts import get_object_or_404
from django.http import HttpResponse
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import employees
from .serializer import employeeSerializer
class employeeList(APIView):
def get(self):
employess1 = employees.objects.all()
serializer = employeeSerializer(employess1 ,many=True)
return Response(serializer.data)
serializer.py
from rest_framework import serializers
from .models import employees
class employeeSerializer(serializers.ModelSerializer):
class Meta:
model = employees
fields = ['first_name','last_name','salary']
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('employees/',views.employeeList.as_view()),
]
You are missing the request argument in the get method. See the docs here
class employeeList(APIView):
def get(self, request):
employess1 = employees.objects.all()
serializer = employeeSerializer(employess1 ,many=True)
return Response(serializer.data)
I have a users app in a Django project (version 2.1 and python 3.6). After an user signup (both front end and when added in the admin dashboard ideally), I'd like to insert data in one other table. I know how to insert data, but I didn't find out how to do it right after a successfull signup.
Ideal answer would just show me how to do something like print('hello') right after an user created his account.
# users/admin.py
from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin
from .forms import CustomUserCreationForm, CustomUserChangeForm
from .models import CustomUser
class CustomUserAdmin(UserAdmin):
add_form = CustomUserCreationForm
form = CustomUserChangeForm
model = CustomUser
list_display = ['email', 'username',]
admin.site.register(CustomUser, CustomUserAdmin)
# users/forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import CustomUser
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm):
model = CustomUser
fields = ('username', 'email')
class CustomUserChangeForm(UserChangeForm):
class Meta:
model = CustomUser
fields = ('username', 'email')
# users/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
class CustomUser(AbstractUser):
# add additional fields in here
credit = models.IntegerField(default=200) # editable=False
def __str__(self):
return self.email
# users/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('signup/', views.SignUp.as_view(), name='signup'),
]
# users/views.py
from django.urls import reverse_lazy
from django.views import generic
from .forms import CustomUserCreationForm
class SignUp(generic.CreateView):
form_class = CustomUserCreationForm
success_url = reverse_lazy('login')
template_name = 'signup.html'
Use a post-save signal
https://docs.djangoproject.com/en/2.1/ref/signals/
from django.db.models.signals import post_save
from django.dispatch import receiver
#receiver(post_save, sender=User)
def say_hello(sender, instance, **kwargs):
if instate._state.adding:
print('hello')
Signal is better than a method on the view because the User may be created some way other than through the view e.g , via the shell, a management command, a migration, a different view, etc.
Note the _state is not "private" so don't feel bad about using it, it's just named that way to avoid clashing with field names.
Check _state instead of more common checking instance.pk because instance.pk is always present when primary key is a natural key rather than AutoField
I think the best approach would be overriding save method of CustomUser model. For example:
class CustomUser(AbstructUser):
def save(self, *args, **kwargs):
user = super(CustomUser, self).save(*args, **kwargs)
print("Hello World")
return user
Check here in Django documentation for more details: https://docs.djangoproject.com/en/2.1/topics/db/models/#overriding-predefined-model-methods.
This is my original thought on how to accomplish this:
products = Product.objects.all()
for product in products:
if product in cart:
products = Product.objects.exclude(product)
My two questions are:
1.) Does this work/ make sense?
2.) Which .py file would I put it in?
views.py
from django.shortcuts import render
from django.shortcuts import HttpResponseRedirect
from django.core.urlresolvers import reverse
from .models import Dropoff, DropoffItem
from products.models import Product
from .forms import AddDropoffItemForm
from django.contrib.auth.models import User
from django.contrib import messages
from django.contrib.auth.decorators import login_required
def add_item_dropoff_order(request):
request.session.set_expiry(120000)
try:
user = request.user
the_id = request.session['dropoff_id']
dropoff = Dropoff.objects.get(id=the_id)
except:
user = request.user
new_dropoff_order = Dropoff(user=user)
new_dropoff_order.save()
request.session['dropoff_id'] = new_dropoff_order.id
the_id = new_dropoff_order.id
dropoff = Dropoff.objects.get(id=the_id)
try:
product = Product.objects.get(sku=sku)
except Product.DoesNotExist:
pass
except:
pass
form = AddDropoffItemForm(request.POST or None)
if request.method == "POST":
product_sku = str(request.POST['product'])
dropoff_item = DropoffItem.objects.create(dropoff=dropoff, product_id=product_sku)
dropoff_item.save()
return HttpResponseRedirect('%s'%(reverse('add_item_dropoff_order')))
context = {
"dropoff": dropoff,
"form": form,
}
return render(request, 'dropoffs/add_item_dropoff_order.html', context)
forms.py
from django import forms
from .models import Dropoff, DropoffItem
from products.models import Product
class AddDropoffItemForm(forms.ModelForm):
product = forms.ModelChoiceField(queryset=Product.objects.all(), widget=forms.Select(attrs={'class':'form-control'}))
class Meta:
model = DropoffItem
fields = ["product"]
So basically, once dropoff_item.save() occurs, I want to remove that product from the queryset being called in the forms.py file.
Is it possible to redefine the queryset in the views and then call it again in the forms.py?
No, not really :) I would approach this like:
products = Product.objects.exclude(id__in=cart.product_ids)
Without seeing your application logic, it's impossible to tell you where to put this code, but since you've tagged django views, I'm assuming you want it in a view.