Problem using generic views in django - django

I'm currently working with django generic views and I have a problem I can't figure out.
When using delete_object I get a TypeError exception:
delete_object() takes at least 3 non-keyword arguments (2 given)
Here is the code (I have ommited docstrings and imports):
views.py
def delete_issue(request, issue_id):
return delete_object(request,
model = Issue,
object_id = issue_id,
template_name = 'issues/delete.html',
template_object_name = 'issue')
urls.py
urlpatterns = patterns('issues.views',
(r'(?P<issue_id>\d+)/delete/$', 'delete_issue'),
)
The other generic views (object_list, create_object, etc.) work fine with those parameters. Another problem I have is when using the create_object() function, it says something about a CSRF mechanism, what is that?

You need to provide post_delete_redirect, this means url, where user should be redirected after object is deleted. You can find this in view signature:
def delete_object(request, model, post_delete_redirect, object_id=None,
slug=None, slug_field='slug', template_name=None,
template_loader=loader, extra_context=None, login_required=False,
context_processors=None, template_object_name='object'):

Related

Wagtail: Add method to PageModel to get an inspect url

I am trying to add a dynamic instead of a hard coded get_inspect_url method to a PageModel:
class MyModel(Page):
# ...
# this is what I have now, which breaks in prod due to a different admin url
def get_inspect_url(self):
inspect_url = f"/admin/myapp/mymodel/inspect/{self.id}/"
return inspect_url
I know that you can use the ModelAdmin.url_helper_class in wagtail_hooks.py to get admin urls for an object, but I can't figure a way to do the same on the model level as a class method. Is there a way?
thanks to #Andrey Maslov tip I found a way:
from django.urls import reverse
def get_inspect_url(self):
return reverse(
f"{self._meta.app_label}_{self._meta.model_name}_modeladmin_inspect",
args=[self.id],
)
The basic form of a Wagtail admin url is:
[app_label]_[model_name]_modeladmin_[action]
Just change the [action] to one of the following to generated other instance level admin urls:
edit
delete
if you have in you urls.py line like this
path(MyModel/view/<id:int>/', YourViewName, name='mymodel-info'),
then you can add to your models.py this lines
from django.urls import reverse
...
class MyModel(Page):
def get_inspect_url(self):
inspect_url = reverse('mymodel-info', kwargs={'id': self.id})
return inspect_url

DJANGO Generic Views: How to use reverse() in get_absolute_url method?

I'm trying to implement generic editing views as shown here:
I started with the CreateView which renders and submits data correctly. However, I am getting an error when I tries to use reverse() to return to the detail view page for the new object.
Here is my Error message:
NoReverseMatch at /work/clients/create/
Reverse for 'ClientDetailView' with arguments '('14',)' and keyword arguments '{}' not found. 0 pattern(s) tried: []
Here is how I defined get_absolute_url() in my model:
def get_absolute_url(self):
return reverse('ClientDetailView', kwargs={'pk': self.pk})
My view is called ClientDetailView. I'm not sure what other information would be helpful.
Here is class ClientDetailView:
class ClientDetailView(generic.DetailView):
model = Client
template_name = 'work/client_detail.html'`
and here is url() from urls.py:
url(r'^clients/(?P<pk>[0-9]+)/$', views.ClientDetailView.as_view(), name='clients_detail'),`
Can anyone explain what I am doing wrong?
I solved my own problem. I had to add the namespace to the reverse() method:
return reverse('work:clients_detail', kwargs={'pk': self.pk})
I would appreciate if someone else could explain why I needed to do this.
Here is the my complete urls.py:
from django.conf.urls import url
from . import views
app_name = 'work'
urlpatterns = [
url(r'^work_orders/$', views.WorkOrdersIndexView.as_view(), name='quotes_index'),
url(r'^work_orders/(?P<pk>[0-9]+)/$', views.WorkOrdersDetailView.as_view(), name='work_orders_detail'),
url(r'^quotes/$', views.QuotesIndexView.as_view(), name='quotes_index'),
url(r'^quotes/(?P<pk>[0-9]+)/$', views.QuotesDetailView.as_view(), name='quotes_detail'),
url(r'^project/(?P<pk>[0-9]+)/$', views.ProjectDetailView.as_view(), name='project_detail'),
url(r'^project/create/$', views.ProjectCreateView.as_view(), name='project_create'),
url(r'^project/(?P<pk>[0-9]+)/update/$', views.ProjectUpdateView.as_view(), name='project_update'),
url(r'^project/(?P<pk>[0-9]+)/delete/$', views.ProjectDeleteView.as_view(), name='project_delete'),
url(r'^clients/$', views.ClientView.as_view(), name='client_index'),
url(r'^clients/(?P<pk>[0-9]+)/$', views.ClientDetailView.as_view(), name='clients_detail'),
url(r'^clients/create/$', views.ClientCreateView.as_view(), name='client_create'),
url(r'^clients/(?P<pk>[0-9]+)/update/$', views.ClientUpdateView.as_view(), name='clients_update'),
url(r'^clients/(?P<pk>[0-9]+)/delete/$', views.ClientDeleteView.as_view(), name='clients_delete'),
]
actually you are trying to reverse the view, instead of ClientDetailView
use url name clients_detail

get a variables by GET in method get in DetailView django

Im trying to get the variable "segundos" by GET in the Detail View, im trying to get it by the method get:
the js file:
$(document).ready(function(){
var segundos=340;
console.log(segundos);
$.ajax({
data : {'segundos':segundos},
url : '/ajax/puzzle-1/',
type : 'GET',
});
});
views.py
class PuzzleView(DetailView):
model = Puzzle
template_name = 'puzzle.html'
def get (self,request,*args,**kwargs):
seconds = request.GET["segundos"]
self.object = self.get_object()
ranking = Ranking.objects.create(puzzle_id=self.object.id,usuario=self.request.user,segundos=seconds,puesto=89)
context = self.get_context_data(object=self.object)
return self.render_to_response(context)
class RankingView(ListView):
model = Ranking
template_name = 'ranking.html'
queryset = Ranking.objects.filter(puzzle_id=1).order_by('segundos')[:3]
class PuzzleAjaxView(TemplateView):
template_name = 'ranking.html'
But i get the famous error "MultiValueDictKeyError". If i try the same method "get" but with a TemplateView, i can get the variable, but not with DetailView
Just in case, my urls.py:
urlpatterns = patterns('puzzle.views',
url(r'^actividad/puzzle/(?P<slug>[-_\w]+)/$',PuzzleView.as_view(),name='puzzle'),
url(r'^ajax/puzzle-1/.*$', PuzzleAjaxView.as_view(),name='ajax'),
url(r'^ranking/.*$', RankingView.as_view(),name='ranking'),
)
seconds = request.GET("segundos")
You can't just call the GET MultiValueDict. You must access by dictionary lookup. It is a subclass of a dict.
request.GET.get('segundos')
request.GET['segundos']
Update
For future reference, your exception traceback would have explained all of this, but the error message should be pretty clear: something along the lines of segundos not being a valid key in the MultiValueDict.
I assume your PuzzleView (what you are calling the DetailView) never gets passed any GET parameters because your example shows GET params only with your AJAX call, which is mapped to your PuzzleAjaxView (what you are calling the TemplateView
What is determining whether or not your get function works or not isn't based on the fact that your view class is a TemplateView or DetailView, it's the fact that segundos is only passed to your AJAX view.
In other words.. any view (TemplateView, DetailView, doesn't matter) accessing a GET dict via direct lookup request.GET['foobar'] will fail if that get parameter isn't passed in.

Django Haystack custom SearchView for pretty urls

I'm trying to setup Django Haystack to search based on some pretty urls. Here is my urlpatterns.
urlpatterns += patterns('',
url(r'^search/$', SearchView(),
name='search_all',
),
url(r'^search/(?P<category>\w+)/$', CategorySearchView(
form_class=SearchForm,
),
name='search_category',
),
)
My custom SearchView class looks like this:
class CategorySearchView(SearchView):
def __name__(self):
return "CategorySearchView"
def __call__(self, request, category):
self.category = category
return super(CategorySearchView, self).__call__(request)
def build_form(self, form_kwargs=None):
data = None
kwargs = {
'load_all': self.load_all,
}
if form_kwargs:
kwargs.update(form_kwargs)
if len(self.request.GET):
data = self.request.GET
kwargs['searchqueryset'] = SearchQuerySet().models(self.category)
return self.form_class(data, **kwargs)
I keep getting this error running the Django dev web server if I try and visit /search/Vendor/q=Microsoft
UserWarning: The model u'Vendor' is not registered for search.
warnings.warn('The model %r is not registered for search.' % model)
And this on my page
The model being added to the query must derive from Model.
If I visit /search/q=Microsoft, it works fine. Is there another way to accomplish this?
Thanks for any pointers
-Jay
There are a couple of things going on here. In your __call__ method you're assigning a category based on a string in the URL. In this error:
UserWarning: The model u'Vendor' is not registered for search
Note the unicode string. If you got an error like The model <class 'mymodel.Model'> is not registered for search then you'd know that you haven't properly created an index for that model. However this is a string, not a model! The models method on the SearchQuerySet class requires a class instance, not a string.
The first thing you could do is use that string to look up a model by content type. This is probably not a good idea! Even if you don't have models indexed which you'd like to keep away from prying eyes, you could at least generate some unnecessary errors.
Better to use a lookup in your view to route the query to the correct model index, using conditionals or perhaps a dictionary. In your __call__ method:
self.category = category.lower()
And if you have several models:
my_querysets = {
'model1': SearchQuerySet().models(Model1),
'model2': SearchQuerySet().models(Model2),
'model3': SearchQuerySet().models(Model3),
}
# Default queryset then searches everything
kwargs['searchqueryset'] = my_querysets.get(self.category, SearchQuerySet())

Django - reversing wrapped view functions

I am trying to incorporate django-schedule into my project. Django-schedule's source is here. I don't like the urls, because they all capture a slug. My project will only allow one calendar per user, so it doesn't make sense to capture the slug. So, I wrapped the django-schedule views like this (look up the slug using the current user, and pass it to django-schedule's views):
from schedule.views import calendar_by_periods
from schedule.models import Calendar
from schedule.periods import Month
def cal_by_periods_wrapper(view):
def new_view(request, *args, **kwargs):
kwargs['calendar_slug'] = Calendar.objects.get_calendars_for_object(obj=request.user, distinction="owner")[0].slug
return view(request, *args, **kwargs)
return new_view
And here is the relevant section from urls.py:
urlpatterns = patterns('',
url(r'^$',
cal_by_periods_wrapper(calendar_by_periods),
name = "month_calendar",
kwargs={'periods': [Month], 'template_name': 'schedule/calendar_month.html'}),
This works fine until it hits one of the template tags included with django-schedule, prev_url:
#register.simple_tag
def prev_url(target, slug, period):
return '%s%s' % (
reverse(target, kwargs=dict(calendar_slug=slug)),
querystring_for_date(period.prev().start))
This function raises:
TemplateSyntaxError at /teacher/calendar/
Caught an exception while rendering: Reverse for 'month_calendar' with arguments
'()' and keyword arguments '{'calendar_slug': u'asdf'}' not found.
How can I wrap this view and still make the reverse call work?
This has nothing to do with wrapping the function. It's just that you no longer have a URL with the name 'month_calendar' which takes a 'calendar_slug' argument. Either define one in your urlconf, or edit the templatetag.
Edit after comment Yes but the 'reverse' call is still passing a slug argument, and there's no 'month_calendar' url which takes one, so the reverse match fails.