I am trying to pass some information to a view in Django in order to filter a list and then pass this back to the user. In order to do so I have the following in my urls.py:
url(r'^info/user/(?P<user_id>\d+)$', views.UserInfoView, name='active_reservations'),
and the following view defined:
def UserInfoView(request, **kwargs):
template = "parking/detail_user.html"
user = User.objects.filter(user=self.kwargs['user_id'])
context = {"user": user}
return render(request, template, context)
However, each time I try this I get the error: NameError at /info/user/1
global name 'self' is not defined
Any ideas?
You should change the view function. Replace **kwargs with user_id
def UserInfoView(request, user_id):
template = "parking/detail_user.html"
user = User.objects.filter(user=user_id)
context = {"user": user}
return render(request, template, context)
kwargs is not an attribute of self. Your code should be:
user = User.objects.filter(user=kwargs['user_id'])
Related
I'm new to Django Class Based Views and I can't get my form to pass through neither form_valid() nor form_invalid().
I have taken most of this code from the Django allauth module, so I extend some mixins (AjaxCapableProcessFormViewMixin & LogoutFunctionalityMixin) that I do not know well.
This form is meant to allow users to change their passwords upon receiving an email. As it is now, users are able to change their password but since the form_valid() function is never triggered, they do no get redirected to the success URL as is intended. Instead the password change is registered but the users stay on the same page.
The functions dispatch(), get_form_kwargs() & get_form_class() are all triggered and behave in the way that they should. Still, it's unclear to me why they execute in the order that they do (dispatch() is triggered first, then get_form_class() and finally get_form_kwargs(). I suppose they implicitely have an order as presented in this documentation: https://ccbv.co.uk/projects/Django/4.0/django.views.generic.edit/FormView/)
I am lacking some intuition about how this works, therefore I don't know if there is a way to redirect to the success URL without passing through form_valid() because that would also solve my problem.
As is mentionned in the title, neither form_valid() nor form_invalid() is triggered after submitting a new password. The last executed bit of code is the return kwargs from the get_form_kwargs() function.
Here is my code:
class PasswordResetFromKeyView(AjaxCapableProcessFormViewMixin, LogoutFunctionalityMixin, FormView):
template_name = "account/password_reset_from_key." + app_settings.TEMPLATE_EXTENSION
form_class = ResetPasswordKeyForm
success_url = '/'
reset_url_key = "set-password"
def get_form_class(self):
return get_form_class(
app_settings.FORMS, "reset_password_from_key", self.form_class
)
def dispatch(self, request, uuid, **kwargs):
self.request = request
token = get_object_or_404(ResetToken, token=uuid)
if token.redeemed == False:
self.reset_user = token.client
self.token = token
response = self.render_to_response(self.get_context_data(token_fail=False))
else:
return super(PasswordResetFromKeyView, self).dispatch(
request, uuid, **kwargs
)
return response
def get_form_kwargs(self, **kwargs):
kwargs = super(PasswordResetFromKeyView, self).get_form_kwargs(**kwargs)
kwargs["user"] = self.reset_user
if len(kwargs) > 3:
try:
if kwargs['data']['password1'] == kwargs['data']['password2']:
self.reset_user.set_password(kwargs['data']['password1'])
self.reset_user.save()
self.token.redeemed = True
self.token.date_redeemed = datetime.now()
self.token.save()
perform_login(
self.request,
self.reset_user,
email_verification=app_settings.EMAIL_VERIFICATION,
)
else:
pass
##passwords dont match
except:
##couldnt change the password
pass
return kwargs
def form_valid(self, form, **kwargs):
form.save()
return super(PasswordResetFromKeyView, self).form_valid(form)
def form_invalid(self, form):
response = super().form_invalid(form)
if self.request.accepts('text/html'):
return response
else:
return JsonResponse(form.errors, status=400)
If both methods are not triggered, it means - you requests.method is never is 'POST'.
The class FormView calls this two methods only if post.method == 'POST':
# code from django.views.generic.edit
...
def post(self, request, *args, **kwargs):
"""
Handle POST requests: instantiate a form instance with the passed
POST variables and then check if it's valid.
"""
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
By the way in dispatch, if token.redeemed == False you should return self.form_invalid().
I have this permission in Django that look like this:
class PermissionName(BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in SAFE_METHODS:
return True
#I want to extract the pk or id params in here.
return False
Can anybody help me get the params of request I tried using self.kwargs["pk"], request.POST['pk'] but they all return saying object has no attribute.
If pk is a parameter of the POST request, you can access it with request.POST.get('pk'). In your post, you are not using get(), so that could be the issue.
If the object is provided as an argument to the function, I'm assuming you want the ID of it. That can also be achieved with obj.id.
lets say your path is:
path('listings/get/category/<str:pk>/', endpoints.HousesWithSameCategory.as_view()),
Your request: api/listings/get/category/1/
In your class method view use:
def get_queryset(self):
print(self.kwargs)
This will return {'pk': '1'}
self.kwargs will return all your dynamic params
If you have only one pk in your url and you use has_object_permission then.
class PermissionName(BasePermission):
def has_object_permission(self, request, view, obj):
obj.pk # To get object id.
But what if you have more then two pk in your url
urls.py
path("buildings/<int:pk>/units/<int:unit_pk>/")
Then you can get pk's from view attribute.
class PermissionName(BasePermission):
def has_object_permission(self, request, view, obj):
print(view.kwargs)
Results:
{'pk': 13, 'unit_pk': 71}
I'm attempting to set up an index page in django that serves different content based on the user permissions (2+ types of users). I've looked into using the #permission_required decorator but it seems a bit wasteful and repetitive to use that with a view that's been mostly repeated. There's also no good fallback method that I can see (I can't do a #permission_required(!'jobs.can_edit')).
views.py:
#permission_required('jobs.can_add')
def index(request):
jobs = Job.objects.all
context = {
"jobs": jobs,
}
return render(request, 'jobs/index.html', context)
#permission_required('jobs.can_edit')
def index(request):
jobs = some.different.data
context = {
"jobs": jobs,
}
return render(request, 'jobs/index.html', context)
Is there an easier way to hook this into the index function and change the context based on user permissions? My ideal scenario would be more like this
imaginary views.py:
def index(request):
if user.can_add:
context = x
return render(request, 'jobs/index/can-add.html', context)
context = y
return render(request, 'jobs/index/can-edit.html', context)
I've also set the three user groups up by name, but I don't see much documentation on accessing group names.
If you are using django permission then you can do this in view
def index(request):
if request.user.has_perm('app_name.permission_name'):
#return something if true
#return something in else case
I recommend using groups and assigning permission to a group and check if a user belongs to a group in the view
try this.
I was inspired with that and I want to share my response too for others but in my case I use DRF and django group.
class ShopOrderCreateList(APIView):
permission_classes = [AllowAny]
#staticmethod
def get_object(shop_id):
try:
return Shop.objects.get(id=shop_id)
except Shop.DoesNotExist:
raise Http404
def get(self, request, shop_id=None):
shop = self.get_object(shop_id)
orders = Order.objects.filter(shop__id=shop.id)
# orders = manager.order_set.all()
# shop_orders = shop
# order_numbers = orders.count()
serializer = OrderSerializer(orders, many=True)
return Response(serializer.data)
#staticmethod
def post(request, shop_id=None):
if request.user.groups.filter(name='admin').exists():
manager = request.user.manager
elif request.user.groups.filter(name='master').exists():
master = request.user.master
manager = master.manager
I have tried following this suggestion to pass string parameters to a class based view but it does not seem to work.
the url:
url(r'^chart/(?P<chart_name>\w+)/$',
ChartView.as_view(chart_name='chart_name'), name="chart_url"),
the view:
class ChartView(View):
template_name = "chart.html"
chart_name = None
def post(self, request, *args, **kwargs):
form = DatesForm(request.POST)
context = {
'form': form
}
return render(request, self.template_name, context)
def get(self, request, *args, **kwargs):
print("test")
form = DatesForm()
# fetch plot data (default values used)
context = {
'form': form,
'chart_name': self.chart_name
}
return render(request, self.template_name, context)
the link that is supposed to be redirecting to the view:
Sometext
(namespace 'chartboard' given in the project's urlconf).
the error:
NoReverseMatch at /chart/lords/
Reverse for 'chart_url' with arguments '()' and keyword arguments '{}' not found. 1 pattern(s) tried: ['chart/(?P<chart_name>\\w+)/$']
For what its worth, "test" gets printed twice to the console output (why?)
Using django 1.8.11 and python 3.4.3 on Ubuntu 14.04.04
You should access the chart_name using kwargs:
# urls.py
url(r'^chart/(?P<chart_name>\w+)/$',
ChartView.as_view(), name="chart_url"),
# and then in the view
class ChartView(View):
template_name = "chart.html"
def get(self, request, *args, **kwargs):
form = DatesForm()
context = {
'form': form,
'chart_name': kwargs['chart_name'] # here you access the chart_name
}
return render(request, self.template_name, context)
The post you have considered for implementing this is for making sure that a variable is available in templates and that is taken care of by setting it up in context which is passed to the template render.
The problem you are facing here is to access a named group defined in the url pattern.
Here is more documentation on how django process a request when you try to access a URL.
I have a class based view in which I process the form and redirect the user on successful submission like so:
views.py
def get(self,request):
form = self.form_class()
return render(request, template_name, { 'form' : form })
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
...
return HttpResponseRedirect(reverse('success'))
return render(request, template_name, { 'form' : form })
urls.py
...
url(r'^submit/success', SubmitView.as_view(), name='success'),
...
It is possible to access url directly by typing success/submit. I don't use any authentication on the site and want the user only be able to access the submit/success page after redirection, so that they are not able to access it directly. How do I do it?
If you are using sessions, you can accomplish it like so:
# in the view where form is submitted
if form.is_valid():
request.session['form-submitted'] = True
return HttpResponseRedirect(reverse('success'))
# in the success view
def get(self, request):
if not request.session.get('form-submitted', False):
# handle case where form was not submitted
else:
# render the template
Instead of redirecting, you could POST to the 'success' page.
Then use if request.method == 'POST':
But beware, this is NOT secure, as headers can be spoofed.
Better to just call the success view from within the POST method, I think.
Have you tried something like this:
if form.is_valid():
...
return HttpResponseRedirect(SubmitView.as_view())
Not sure if this works out of the box, but with a few more tricks you might get what you want.
To add to the answer #miki725 posted I would also make sure you change
request.session['form-submitted'] = False
after you have entered the
if not request.session.get('form-submitted', False):
In order to prevent accessing the page directly or using the back and forward on the browser.