Django 1.9 get kwargs in class based view - python

I was wondering if there is a way to get the kwargs directly in a class based view. I know this can be done in functions inside the class, but I'm having problems when I try this:
views.py
class EmployeesUpdateStudies(UpdateView):
form_class = form_ES
model = EmployeePersonal
template_name = 'employeesControll/employees_studies_update_form.html'
success_url = reverse('employee-details', kwargs={'pk': kwargs.get('pk')})
My url is the following
url(r'^employees/detalles/(?P<pk>[0-9]+)/$', login_required(views.EmployeeDetails.as_view()), name='employee-details')

Alasdair's answer solves your problem. You can however define a get_absolute_url method for your EmployeePersonal model which will act as the success_url for your view:
You don’t even need to provide a success_url for CreateView or
UpdateView - they will use get_absolute_url() on the model object
if available.
You'll use self.id in the get_absolute_url method for the model objects primary key.
Reference:
Model Forms

You can't use kwargs in success_url, because when Django loads the class when the server starts, it doesn't have access to the request. Override the get_success_url method instead.
def get_success_url(self)
return reverse('employee-details', kwargs={'pk': self.kwargs['pk']})

Related

How to pass additional arguments to class view in django?

def edit_course(request,course_id):
course=Courses.objects.get(id=course_id)
return render(request,"hod_template/edit_course_template.html",{"course":course,"id":course_id})
The code above shows a view in django that is defined as a function. I want to recreate the same view as a class based view in django but I couldn't pass in an additional argument such as course_id into the class based view as it shows an error. Can someone tell me how to recreate that above function into a class based view ?
You can make a DetailView with 'course_id' as pk_url_kwarg. An equivalent DetailView is:
from django.views.generic import DetailView
class EditCourseView(DetailView):
model = Courses
pk_url_kwarg = 'course_id'
context_object_name = 'course'
template_name = 'hod_template/edit_course_template.html'
Note: normally a Django model is given a singular name, so Course instead of Courses.
Possible duplicate of URL-parameters and logic in django...
You can access your course_id via
self.kwargs['course_id']
Use it inside class-based view functions

I keep getting this error 'Manager isn't accessible via Post instances' in django 1.10

Here are my codes in models.py
class PublishedManager(models.Manager):
def get_queryset(self):
return super(PublishedManager,self).get_queryset().filter(status='published')
A manager needs to be used with a model and not a queryset.
pm = PublishedManager() #in model
then if 'Post' is the model class
Post.pm.all()
You cant use objects or querysets of Post.

Filtering Objects in Class based view Django using Query parameters?

I am using Class-based Generic views Listview for listing all objects.
My views.py:
class PostsList(ListView):
model = Post
template_name = "index.html"
My Urls.py:
urlpatterns = [
url(r'^$',PostsList.as_view(), name = "home"),
]
This gives me a list of all the posts. Now I want to filter/sort posts based on certain fields of Post Model, say price. Do I need to write this myself? If yes Which method of PostsLists class do I override ? def get, def get_context ?
I see the get method for Listview defined as below. In it can I pass URL query-parameters as **kwargs directly or I have to overwrite the below method in my class.
def get(self, request, *args, **kwargs):
....
You can override the get_queryset method:
Keep a mapping of all the parameters that you can get in the url kwargs.
def get_queryset(self):
queryset = Post.objects.all()
if self.request.GET.get('price'):
queryset = queryset.filter(price=self.request.GET.get('price'))
return queryset
When using Django's class based views, avoid overriding get() or post() if possible. These methods do a lot, and if you override them, you may have to duplicate a lot of the built in functionality. There are normally more specific methods that you can override.
In your case, you can filter the queryset dynamically with the get_queryset method. You can access GET parameters with self.request.GET. For example:
class PostsList(ListView):
model = Post
def get_queryset(self):
"""Filter by price if it is provided in GET parameters"""
queryset = super(PostsList, self).get_queryset()
if 'price' in self.request.GET:
queryset = queryset.filter(price=self.request.GET['price'])
return queryset
If your url captures arguments, you can access them with self.args (positional) and self.kwargs (name based).
See the docs on dynamic filtering for more info.

Access model name in Django CreateView from template

I'm using the generic CRUD views in Django 1.6, e.g.:
class KanriCreateView(CreateView):
template_name = 'generic_form.html'
class KanriUpdateView(UpdateView):
template_name = 'generic_form.html'
etc.
N.B. These are classes used as a base class which I subclass inside views.py files throughout the project.
In order to keep DRY I'm writing a generic form template for all create/update views.
For update views, I have access to object in the template, which is the instance I am updating. I then use object.__class__.__name__ (via a custom filter) to get the name of the class (so I can have automatically generated custom buttons like "Add User", "Add Role".etc so the forms look less...generic.
Of course, when I'm using my template in CreateView, object does not exist (as it has not been created), so my custom buttons.etc do not work, and I get a VariableDoesNotExist exception.
Does Django provide the class somewhere so I can use it in the template?
The name of your first view should be different, e.g. KanriCreateView
It might help you to get the name of the view class: {{ view.class.name }}
If you have access to the view class (which is provided by default by the ContextDataMixin) you can access the model attribute of the view class and get the name of the model: {{ view.model.__name__ }}
Cheers
If you're using a ModelForm for your CreateView, this doesn't quite work. This is because you're not specifying
model = MyModel
but instead you're specifying
form_class = MyModelForm
so what you can do instead is
from django.contrib.admin.utils import model_ngettext
model_ngettext(self.form_class._meta.model, 1)
I propose a solution updated for Django 2 and 3: retrieve the model verbose name from the ModelForm associated to the CreateView.
class YourCreateView(CreateView):
form_class = YourModelForm
def get_context_data(self, **kwargs):
"""Add the models verbose name to the context dictionary."""
kwargs.update({
"verbose_name": self.form_class._meta.model._meta.verbose_name,})
return super().get_context_data(**kwargs)
Now you can use {{ verbose_name }} inside your template.
Please, remark the double _meta in the code snippet above: the first is meant to access the model from the ModelForm, while the second accesses the verbose name of the Model.
As with internationalization, remark that if your model uses ugettext as shown below, then the verbose name will automatically be translated in the template.
from django.utils.translation import ugettext_lazy as _
class MyModel(models.Model):
class Meta:
verbose_name = _("your verbose name")

Django filtering and deleting

I have this modelViewSet
class LikeViewSet(viewsets.ModelViewSet):
queryset = Likes.objects.all()
serializer_class = LikeSerializer
filter_fields = ('user','post')
def delete(self, request, pk, format=None):
post = Likes.objects.get(pk=pk)
post.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
I'm trying to filter using the url such as:
http://localhost:8000/likes/?user=anon&post=1
And then delete that specific result that I get from django but django keeps on giving me
delete() takes at least 3 arguments (2 given)
I can't really figure out why. Can anyone help please? Thanks! I'm using Django Rest Framework
EDIT: This is the model for the LikeViewSet:
class Likes(models.Model):
user = models.ForeignKey(Profile, related_name='liker')
post = models.ForeignKey(Post, related_name=' post' )
created = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('created',)
The idea is, it's a model table for a relationship between a user model and a post model so the filtering has to be done in the url that way
When you're using a ViewSet, you should use the destroy() method rather than delete().
See documentation here:
A ViewSet class is simply a type of class-based View, that does not
provide any method handlers such as .get() or .post(), and instead
provides actions such as .list() and .create().
Based on your code, it doesn't look like you're doing anything unique in the destroy/delete method. Are you fine with just using the default destroy function?

Categories