django haystack - how to use with current view having some context - python

I have a view that puts some context and renders the template from this context. I want view display all the things if no search query is there, and show searhed things, if anything searched.
class MyCurrentView(View):
def get(self, request):
data = { 'users': User.objects.all() }
return render_to_response("mytemp.html", ..
urls.py:
url(r'^search/$', MyCurrentView.as_view())
Now, I am integrating this with SEarchView like this:
class MyCurrentView(SearchView): (If u observe, I subclassed SEarchView).
template = 'mytemp.html'
def get(self, request):
data = { 'users': User.objects.all() }
return render_to_response...
def get_context_data(self, ...):
print "....this should print" #But not printing. So, unable to add data
return data
urls.py:
url(r'^search/$', MyCurrentView.as_view())
# as_view() gave me error, so I did MyCurrentView() , may be thats y, get_context_data not calling.
Will provide more information if necessary.

New Django-style class based views were added via PR #1130 to django-haystack:
https://github.com/toastdriven/django-haystack/pull/1130
You can now use search views like you normally would with django (see changes in pull request).
from haystack.generic_views import SearchView
class MySearchView(SearchView):
def get_context_data(self, **kwargs):
# do whatever you want to context

Related

How to list all objs and retrieve single obj using django drf generic views

I am trying to create a single class based view for retrieving, listing, and creating all of my orders. I have gotten create and retrieve to work but listing is giving some problems. I am using DRF generic views to extend my view and have added the generics.ListApiView to my class. Once I added this however my retrieve route started acting unusual. It is returning to me a list of all the orders when I just want a specific one.
I tried to just add the generics.ListApiView to my class and override the list and get_queryset functions but that just started to affect my retrieve view.
class Order(generics.ListAPIView, generics.CreateAPIView, generics.RetrieveAPIView):
permission_classes = (permissions.IsAuthenticated,)
serializer_class = addOrderSerializer
def get_queryset(self, **kwargs):
user = self.request.user
return Order.objects.filter(user=user)
def get_object(self):
pk = self.kwargs['pk']
obj = Order.objects.get(pk=pk)
return obj
def get_item_serializer(self, *args, **kwargs):
return addItemSerializer(*args, **kwargs)
def get_shipping_serializer(self, *args, **kwargs):
return addShippingSerializer(*args, **kwargs)
def create(self, request, *args, **kwargs):
user = request.user
data = request.data
orderItems = data.get('orderItems')
print(data)
if not bool(orderItems):
return Response('No Order Items', status=status.HTTP_400_BAD_REQUEST)
else:
# TODO - Create Order
orderSerializer = self.get_serializer(data=data)
orderSerializer.is_valid(raise_exception=True)
order = orderSerializer.save(user=user)
# TODO - Create Shipping Address
shippingSerializer = self.get_shipping_serializer(data=data)
shippingSerializer.is_valid(raise_exception=True)
shippingSerializer.save(order=order)
# TODO - Create Order Items and Set Order <> OrderItem Relationship
for item in orderItems:
product = Product.objects.get(pk=item['product'])
itemSerializer = self.get_item_serializer(data=item)
itemSerializer.is_valid(raise_exception=True)
item = itemSerializer.save(order=order, product=product)
# # TODO - Update Product CountInStock
product.countInStock -= item.qty
product.save()
return Response(data=orderSerializer.data)
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
s = self.get_serializer(instance=instance)
return Response(data=s.data)
def list(self, request, *args, **kwargs):
qs = self.get_queryset()
s = self.get_serializer(qs, many=True)
return Response(s.data)
from django.contrib import admin
from django.urls import path, include
from .. import views
urlpatterns = [
path('', views.Order.as_view()),
path('add/', views.Order.as_view()),
path('<int:pk>/', views.Order.as_view({'get':'retrieve'})),
]
So in conclusion the list functionality of my view is working now but it has messed up my retrieve functionality. So that the retrieve function is only returning a list even tho I am adding the pk in my url.
Can you please post your urls.py as well for better clarity ?
Currently based on your question, the issue I see is mentioned below:
You are calling class "Order" for retrieve method with some url pattern eg path/int:pk -- Which is a GET request
You are also calling same class "Order" for list method with some url pattern eg path/ -- Which is a Get request
The issue is that both Retrieve and List Generic api has a GET method: snippet added :
Conclusion:
This is an example of Method Resolution Order in python inheritance.
Therefore, even though you are trying to invoke a GET method for retrieve it is envoking the GET method of LIST api because in your class definition
class Order(generics.ListAPIView, generics.CreateAPIView, generics.RetrieveAPIView) you have inherited ListAPIView first.
Solution :
You should separate out the classes eg: ListCreateAPIView, RetrieveUpdateDestroyAPIView
Alternatively :
You can also follow below stackoverflow answer to route GET request to specific method in same class :
Multiple get methods in same class in Django views
[EDIT]
The above suggested stackoverflow answer seems to be incorrect.
For multiple GET or POST request within same class, you can use Django Viewset and routers.
I found the below link to be well explained with examples:
https://testdriven.io/blog/drf-views-part-3/

Customize django admin. Problem with no-model views

Im trying to create a extra view in django admin, on the left navbar. This view will be responsible for uploading a file, which will be parsed in some function (in future i would like to render result of this parsing in admin page). This file wont be saved in database, so there wont be a model. Is there any possibility to add a view to django admin (left navbar) which dont have a model? I was reading a lot, and could find a solution. What i have done for now:
Created a class which inherits from AdminSite. I tried to implement get_app_list method, but variable self._build_app_dict(request) was empty array, and this means, method couldn't find a installed aps. I wanted to add new object to app_list variable, to render it on website.
Tried to override a admin templates, but couldnt render it. I tried to override app_index.html which i put on folder: app_name/templates/admin/app_index.html
Here is my code, which ofc doesnt work:
class MyCustomAdmin(AdminSite):
def get_app_list(self, request):
"""
Return a sorted list of all the installed apps that have been
registered in this site.
"""
app_dict = self._build_app_dict(request)
breakpoint()
app_list = sorted(app_dict.values(), key=lambda x: x['name'].lower())
for app in app_list:
app['models'].sort(key=lambda x: x['name'])
return app_list
def get_urls(self):
from django.conf.urls import url
urls = super(MyCustomAdmin, self).get_urls()
urls += [
url(r'^my_custom_view/$', self.admin_view(MyCustomView.as_view()))
]
return urls
class MyCustomView(View):
template_name = 'admin/app_index.html'
def get(self, request):
print('fefef')
return render(request, self.template_name, {})
def post(self, request):
pass
admin_site = MyCustomAdmin()
admin_site.get_app_list(AdminSite.get_app_list)

One object only in GET method in Django REST Framework

I have a list of all my objects when I use get method by api/movies in my api, and this is ok. I want also to get only one, specyfic object when use get method by api/movies/1 but now I still have a list of all my objects... What to change in my MoviesView or in urls?
My views.py:
class MoviesView(APIView):
def get(self, request):
movies = Movie.objects.all()
serializer = MovieSerializer(movies, many=True)
return Response(serializer.data)
My appurls.py:
urlpatterns = [
url('movies', MoviesView.as_view(), name="MoviesView"),
]
And my project urls.py:
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include("api.urls")),
]
When I use routers everythig crushes... Could you help me?
You can simply use viewsets.ModelViewSet that natively implements list and retrieve.
You declare something like router.register('movies', my_views.MoviesViewSet) in you urls.py and
class MoviesViewSet(viewsets.ModelViewSet):
queryset = Movie.objects.all()
serializer_class = MovieSerializer
permission_classes = [IsAuthenticated, ]
def get_queryset(self):
return self.queryset
def get_object(self):
movie_id = self.kwargs['pk']
return self.get_queryset().filter(id=movie_id)
def retrieve(self, request, *args, **kwargs):
try:
instance = self.get_object()
except (Movie.DoesNotExist, KeyError):
return Response({"error": "Requested Movie does not exist"}, status=status.HTTP_404_NOT_FOUND)
serializer = self.get_serializer(instance)
return Response(serializer.data)
def list(self, request, *args, **kwargs):
queryset = self.get_queryset()
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
This approach implies that you declare a Serializer, just like:
class MovieSerializer(serializers.ModelSerializer):
class Meta:
model = Movie
fields = '__all__'
Django simply maps HOST/movies/ to list (multiple objects) and HOST/movies/PK/ to retrieve method (one single object).
Docs:
https://www.django-rest-framework.org/api-guide/viewsets/#modelviewset
https://www.django-rest-framework.org/api-guide/serializers/#modelserializer
Hope it helps.
BR.
Eduardo
I would suggest you if you want to retrieve just 1 element to use a Generic View, i.e RetrieveAPIView
It would give you all you need for getting 1 element.
from rest_framework import generics
class MoviesView(generics.RetrieveAPIView):
queryset = Movie.objects.all()
serializer_class = MovieSerializer
but you need also to change urls.py
url(r'movies/(?P<pk>[0-9]+)/$', MoviesView.as_view(), name="MoviesView"),
When you make a GET request to "api/movies/1", the url is matched to the "api/movies" path (read more in the docs), and the MoviesView's get method is called. And your get() implementation just fetches all the movies (movies = Movie.objects.all()), serializes and returns them - that's why you get the entire list.
If you want to retrieve one specific object, you need to somehow specify which object you have in mind, using its primary key (in your case, id).
1. You have to define a separate path: movies/<int:pk>/ (btw, which Django version are you using? url has been deprecated, use path instead!)
2. You have to define a detail view to handle this new case, and pass it to the path function as the second argument.
This general problem can really be solved in many ways, and depending on your app you may want to use a ViewSet instead of views. Then you don't have to define paths (urls) separately - you can use a router. You can't use routers with your view, because router needs a viewset class as its argument.
If you provide more details, I could try to suggest something more specific.
My appurls.py:
use path method
urlpatterns = [
path('movies', MoviesView.as_view(), name="MoviesView"),]
Maybe it works
Start by adding a format keyword argument to both of the views, like so
def snippet_list(request, format=None):
and
def snippet_detail(request, pk, format=None):
Now update the snippets/urls.py file slightly, to append a set of format_suffix_patterns in addition to the existing URLs
from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views
urlpatterns = [
path('snippets/', views.snippet_list),
path('snippets/<int:pk>', views.snippet_detail),
]
urlpatterns = format_suffix_patterns(urlpatterns)

Django contect_object_name is not producing a context dict in view

I am back with more django questions on CBVs. This is about context_object_name. I have the following:
#method_decorator(verified_email_required, name='dispatch')
class Create(CreateView):
model = Profile
context_object_name = 'profileForm'
template_name = 'Members/template_includes/profile/form.html'
form_class = ProfileForm
success_url = '/Members'
form_title = "New Login Profile Information"
def get(self, request, *args, **kwargs):
return render(request, self.template_name, {
'profileTitle': self.form_title,
})
I am using PyCharm and can put a breakpoint in the template_name form and see what the environment knows about. I expect to see a dict named profileForm with all the form members in it plus profileTitle. Instead I see profileTitle as a standalone member. I do not see anything named profileForm or object_list and the expected form members are not being painted in the template.
I suppose that I understand that the extra content in the return render will pass a "naked" profileTitle but I did expect that the default get behaviour would pull in the form info.
Have I missed the point?
You've overridden the get method in your CreateView-subclass and in doing so, you've bypassed the included functionality that a CreateView does to fill your context. If you take a look here you can see that a CreateView would otherwise call return self.render_to_response(self.get_context_data()) (because it inherits from ProcessFormView) and it's within get_context_data() (ref) that those included context variables are set up.

Django 1.9 : Passing arguments from urls.py to a class view

I am creating a small web application as a mini project of mine to learn the Django framework. I'm on Version 1.9.4, on OS X. I'm trying to pass a string in the URL that will be sent to a class-based view, and it will return a different template based on the URL. To my knowledge, doing (?P) will allow the input of dynamic text. \w is for characters, and writing <name> will pass it as a variable. Is this configured right, or is this is not the correct way to do it?
The reason I'm concerned is that the Django documentation uses method views, while I am using class-based views.
urls.py
from django.conf.urls import url
from . import views
app_name = 'xyz'
urlpatterns = [
url(r'^create/(?P<ty>\w+)$', views.ArticleView.as_view(), name='article-form'), #.as_view() to turn Class into View
]
views.py
class ArticleCreate(View):
l = {
'weapon': WeaponForm,
'map': MapForm,
'operator': OperatorForm,
'gadget': GadgetForm,
'skin': SkinForm
}
ty = ty.lower()
template_name = 'xyz/create_article_form.html'
def get(self, request):
return render(request, self.template_name)
def post(self, request):
pass
The arguments that are being passed to the url should be "catched" within the view inside the relevant function, for example:
def get(self, request, ty):
ty = ty.lower()
return render(request, self.template_name)

Categories