how to set cookie in class based generic view - python

newbies to django1.6
i want to set cookie in class based generic view (Listview)
models.py
class Designation(Models.model):
title = models.CharField(max_length=50)
description = models.CharField(max_length=10000, blank=True)
views.py
class DesignationList(ListVew):
def get_queryset(self):
"""
will get 'sort_by' parameter from request,
based on that objects list is return to template
"""
col_nm = self.request.GET.get('sort_by', None)
if col_nm:
if cookie['sort_on'] == col_nm:
objects=Designation.objects.all().order_by(col_nm).reverse()
else:
cookie['sort_on'] = col_nm
objects=Designation.objects.all().order_by(col_nm)
else:
objects = Designation.objects.all().order_by('title')
//set cookie['sort_on']='title'
return objects
template
in template im iterating over objects
so initially objects display in sort_by 'title' desc.
"this values is i want to set in cookie".
in template, if user click over title,it will check in cookie
cookie['sort_on']='title'
then all objects are in asce order
if user click over description,then cookie value is replaced
cookie['sort_on']='description' and objects are in desc order..
soo,how to set cookie which i can use in whole ListView class.. ?
Thnx in advance..

In order to set/delete cookies you have to have access to the "response" object. To do so, in a class-based view, you can override "render_to_response".
Example:
class DesignationList(ListVew):
def render_to_response(self, context, **response_kwargs):
response = super(LoginView, self).render_to_response(context, **response_kwargs)
response.set_cookie('sort_on', 'title')
return response

Unless you have a very good reason, you shouldn't be using cookies, but the session framework. You can access that inside your methods with self.request.session, and it acts like a dictionary.
if col_nm:
if self.request.session.get('sort_on') == col_nm:
objects=Designation.objects.all().order_by(col_nm).reverse()
else:
self.request.session['sort_on'] = col_nm
objects=Designation.objects.all().order_by(col_nm)
etc.

Related

Render fields conditionally with Django-Filters

I'm working on my Django SAAS app in which I want to allow the user to have some custom settings, like disable or enable certain filters. For that I'm using django-user-setttings combined with django-filters and simple forms with boolean fields:
class PropertyFilterSetting(forms.Form):
filter_by_loans = forms.BooleanField(required=False)
filter_by_tenants = forms.BooleanField(required=False)
The issue is that when trying to apply those settings, I keep running into serious spaghetti code:
views.py
class PropertyListView(LoginRequiredMixin, FilterView):
template_name = 'app/property_list.html'
context_object_name = 'properties'
def get_filterset_class(self):
print(get_user_setting('filter_by_tenants', request=self.request))
return PropertyFilterWithoutTenant if not get_user_setting('filter_by_tenants', request=self.request)['value'] else PropertyFilter
filter.py
class PropertyFilter(django_filter.FilterSet):
...
class PropertyFilterWithoutTenant(PropertyFilter):
...
and I'd have to do the same thing with the rest of the features. Is there any better way to implement this?
You can create methods in your User model, or a new class which acts as a store for all the methods. Each method will give you the relevant filterset class based on the value of corresponding user setting.
Something like:
class UserFilterset:
def __init__(self, request):
self.request = request
def get_property_filterset(self):
if not get_user_setting('filter_by_tenants', request=self.request)['value']:
return PropertyFilterWithoutTenant
return PropertyFilter
... # add more such methods for each user setting
Now you can use this method to get the relevant filterset class
class PropertyListView(LoginRequiredMixin, FilterView):
template_name = 'app/property_list.html'
context_object_name = 'properties'
def get_filterset_class(self):
return UserFilterset(self.request).get_property_filterset()
So even if in future you want to add some more logic, you can just update the relevant method, it would be cleaner and manageable.
I'm not sure how MVT stucture will exactly respond to this one but i use a custom generic class in REST structure to add custom filter fields in any viewset that i want
class ListAPIViewWithFilter(ListAPIView):
def get_kwargs_for_filtering(self):
filtering_kwargs = {}
if self.my_filter_fields is not []:
# iterate over the filter fields
for field in self.my_filter_fields:
# get the value of a field from request query parameter
field_value = self.request.query_params.get(field)
if field_value:
filtering_kwargs[field] = field_value
return filtering_kwargs
def get_queryset(self):
queryset = super(ListAPIViewWithFilter, self).get_queryset()
filtering_kwargs = self.get_kwargs_for_filtering()
if filtering_kwargs != {}:
# filter the queryset based on 'filtering_kwargs'
queryset = queryset.filter(**filtering_kwargs)
self.pagination_class = None
else:
return queryset
return queryset[:self.filter_results_number_limit]
changing origional get_queryset function in views.py should be the key to solving your problem (it works in django rest).
try checking what function gets the data then just identify the field wanted from it.

DRF , route a retrieve function to a post function

I have a Django rest framework API that gets a POST request and has a retrive method in the view.
I want that when the user presses the post button it will route the URL to the render created in the retrieve method of the view class.
code:
#views.py
class LocationInfoViewSet(ModelViewSet):
# Order all objects by id, reversed.
queryset = LocationInfo.objects.all().order_by('-id')
serializer_class = LocationInfoSerializer
def retrieve(self, request, *args, **kwargs):
"""
This method is used to get the last object created by the user and render a map associated with the
mission's name.
"""
data = self.queryset[0]
serialized_data = LocationInfoSerializer(data, many=False)
points = list(serialized_data.data.values())
assign_gdt1 = GeoPoint(lat=points[2], long=points[3])
assign_gdt2 = GeoPoint(lat=points[4], long=points[5])
assign_uav = GeoPoint(lat=points[6], long=points[7], elevation=points[-3])
# Geo locations from the POST request.
gdt1 = [assign_gdt1.get_lat(), assign_gdt1.get_long()]
gdt2 = [assign_gdt2.get_lat(), assign_gdt2.get_long()]
uav = [assign_uav.get_lat(), assign_uav.get_long(), assign_uav.get_elevation()]
mission_name = points[1]
try:
# Check if a file already exists in the DB.
HTMLFileInteractionWithDB.table = THREE_POINTS_TRINAGULATION
openfile = HTMLFileInteractionWithDB.return_file_from_db(mission_name=mission_name)
return render(request, openfile)
except:
# Create a new file if one does not exists.
# The main function Creates an HTML File to be rendered.
return render(request, main(gdt1, gdt2, uav,
gdt1_elev=assign_gdt1.get_elevation(),
gdt2_elev=assign_gdt2.get_elevation(),
mission_name=mission_name
)
)
mission name is a primary key, So to access to the retrieve method the user need to go to the URL line and write the mission name for the method to work.
So, how and where in my project (urls,view...) do I create this route.
Exmpale:
I'm a little confused as to the purpose of this view.
The retrieve method is correctly used when it is retrieving a specific object from the queryset list using the pk. IE, one of your LocationInfo objects. It's always a get request.
Your retrieve method is also missing the pk parameter, which is sometimes defaulted as None.
retrieve(self, request, pk=None)
If I were you, I'd create a completely separate view or viewset method/action for this.
Instead of using retrieve for this, we can create a completely new method:
from rest_framework.decorators import action
class LocationInfoViewSet(ModelViewSet):
# Order all objects by id, reversed.
queryset = LocationInfo.objects.all().order_by('-id')
serializer_class = LocationInfoSerializer
# {The rest of your methods, etc...}
#action(detail=False, methods=["post"])
def last_object_by_user(self, request, *args, **kwargs):
# your query to get the last object by your user
queryset = LocationInfo.objects.filter(created_by=request.user).latest()
# The rest of your code
This will create a new endpoint called /{name}/last_object_by_user/ that you can make post requests to.
You'd also notice that I've modified your queryset a bit. Your current queryset gives us the last LocationInfo created by any user. Did you create a field in LocationInfo that tracks who created that LocationInfo?
Here's the documentation for this: Marking extra actions for routing
Note: I did not test this code so if you copy-paste this, it might not work, but the idea is what's important.

How To Initialize A Value in ForeignKey Dropdown from View in Django

I need to set the value of my ForeignKey dropdown = to a url parameter when the form is rendered. I am able to successfully set other form fields to this value, but not the ForeignKey.
I am trying to initialize the 'reference' form field which is a foreign key using the reference_id value which is passed via the url. I can successfully assign this value to the three other fields in the form, but not to 'reference'.
Models.py
class Manifests(models.Model):
reference = models.ForeignKey(Orders)
cases = models.IntegerField()
description = models.CharField(max_length=1000)
count = models.IntegerField()
def __str__(self):
return self.description
Forms.py
class CreateManifestForm(forms.ModelForm):
class Meta:
model = Manifests
fields = ('reference', 'cases', 'description', 'count')
Views.py
def add_manifest(request, reference_id):
if request.method == "POST":
form = CreateManifestForm(request.POST)
if form.is_valid():
instance = form.save(commit=False)
try:
order = Orders.objects.get(id=reference_id)
except Orders.DoesNotExist:
pass
instance.reference = order
instance.save()
return redirect('add_manifest', reference_id=reference_id)
#this is where my problem is
form = CreateManifestForm(initial={'reference': reference_id})
reference = request.POST.get('reference')
manifests = Manifests.objects.all().filter(reference=reference)
context = {
'form': form,
'reference_id': reference_id,
'manifests' : manifests,
}
return render(request, 'add_manifest.html', context)
And just in case it's needed:
urls.py
url(r'^add_manifest/(?P<reference_id>\d+)/$', add_manifest, name='add_manifest'),
There are no errors, but the field does not set to the value passed through the URL. Like I have said if I try
form = CreateManifestForm(initial={'cases': reference_id})
then the cases field does take on that value, so I'm just not sure how to navigate this in the case of a foreign key
First understand the concept here:
class Manifests(models.Model):
# Though this reference store id from Orders
# Its actually a Orders object
reference = models.ForeignKey(Orders)
In Django when-ever we do foreign-key assignment, foreign object's primary key is stored in current objects column in database only, but when we access it in python code, it returns whole foreign object.
Now let's have look at your problem here:
form = CreateManifestForm(initial={'reference': reference_id})
In above code you are initializing CreateManifestFormCreate 'reference' attribute with Integer object which is wrong as it requires Orders object to be assigned.
form = CreateManifestForm(initial={'cases': reference_id})
And above code is running correctly because 'cases' accept Integer object.
So solution to your problem is:
By querying to Orders object by passing the reference_id
form = CreateManifestForm(initial={'reference': Orders.objects.get(id=reference_id)})
Hope this help !!!
Looking at the similar question/answer, you would need to set the Orders instance in initial for the reference field, not just the id of the related object.
Maybe you could try something like this and see if that works:
reference_pk = request.POST.get('reference', '')
reference = Orders.objects.get(pk=reference_pk)
form = CreateManifestForm(initial={'reference': reference})

Django: how to inject data when overriding get_queryset()?

Very begginer with the Django class based view.
I had a ListView that worked well but displayed all the objects. I wanted to filter this, and here what I did, following some examples found:
models.py:
class FolderElement(TimeStampedModel):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
class FolderMedia(TimeStampedModel):
folder_element = models.ForeignKey(FolderElement)
file = models.FileField(upload_to=generate_filepath_folder)
slug = models.SlugField(max_length=50, blank=True)
views.py:
class FolderMediaListView(ListView):
model = FolderMedia
template_name = "book.html"
def get_queryset(self):
self.folder_element = get_object_or_404(FolderElement,
pk=self.kwargs['pk'])
return FolderMedia.filter(folder_element=self.folder_element)
def render_to_response(self, context, **response_kwargs):
files = [ serialize(p) for p in self.get_queryset() ]
data = {'files': files}
response = JSONResponse(data, mimetype=response_mimetype(self.request))
response['Content-Disposition'] = 'inline; filename=files.json'
return response
But now that I overrided the get_queryset() method, I don't understand how I'm supposed to inject the pkparameter to the view sothat the filter works. Currently, using pdb, I can see that self.kwargs equals {} into the get_queryset() method.
Thanks.
The keyword arguments (kwargs) that the Django URL dispatcher passes to the view comes from the following:
Captured parameters in the URL expression
Additional arguments specified in the URL definition
All of them in urls.py.
So, for example, in order to get an ID form the URL in a form: /folder/id/:
url(r'folder/(?P<pk>\d+)/', FolderMediaListView.as_view)
Or if the id is constant (more rarely), you can pass it as an additional argument:
url(r'folder/', FolderMediaListView.as_view, {'pk': 1})
More information on the subject in the Django documentation.
You need to supply it in the URL. For example:
url(r'folder/(?P<id>\d+)/media', FolderMediaListView.as_view, name='folder_media_list')

How to render an html template with data from view?

I am new to django. I made a form. I want that if the form is filled successfully then django should redirect to a success page showing the name entered in the form but no parameters should be present in the url itself.
I searched on the internet and the solution I got was to redirect to url with pk as a get parameter which fetches the data and shows in the view. But I don't want to pass any thing in the url itself. and some websites say that http can't redirect with post data.
Here's my views.py
class UserRegistrationView(CreateView):
model = UserForm
template_name = 'userregistration.html'
form_class = UserForm
success_url = 'success'
def get_success_url(self):
return reverse('success',kwargs = {'name' : self.object.firstName})
and here's the template to which I want to redirect:
<h2>Congratualations for registering {{name}} </h2>
Basically what I want is that if the person fill form mentioning his/her firstName as "xyz" then the redirected success page should say that "Congratulations for registering xyz"
You can use django sessions, which I believe installed by default in 1.8
Look here
# Set a session value:
request.session["fav_color"] = "blue"
# Get a session value -- this could be called in a different view,
# or many requests later (or both):
fav_color = request.session["fav_color"]
# Clear an item from the session:
del request.session["fav_color"]
You can pass your pk via session and extract your object in another view without affecting your url.
Make sure you clean up after yourself.
Let me know if more help needed.
One of the possible ways of passing data between views is via sessions. So, in your UserRegistrationView you need to override the form_valid method as shown below.
class UserRegsitrationView(CreateView):
def form_valid(self,form):
self.request.session['name'] = self.object.firstName
return super(UserRegistrationView,self).form_valid(form)
class SuccessView(TemplateView):
template_name = "success_template.html"
def get_context_data(self,**kwargs):
context = super(SuccessView,self).get_context_data(**kwargs)
context['name'] = self.request.session.get('name')
del self.request.session['name']
return context
One more thing that you can modify in your code is that you need not declare success_url if you are overriding get_success_url

Categories

Resources