Is it possible eliminate pk from url related to UpdateView?
For example, if I have
url(r'^myobj/update/(?P<pk>\d+)/$', views.UpdateMyObj.as_view(), name="update")
is there any way to write it like
url(r'^myobj/update/$', views.UpdateMyObj.as_view(), name="update")
and then send pk as a parameter in POST or GET request?
Yes it is possible you just need to override the get_object method:
from django.views.generic.edit import UpdateView
class UpdateMyObj(UpdateView):
# .....
def get_object(self):
return MyModel.objects.get(pk=self.request.GET.get('pk')) # or request.POST
Sometimes it works like this
class MyViewUpdate(UpdateView):
def get_object(self, queryset=None):
obj = self.model.objects.get(my_id_or_name_of_field=self.kwargs['pk_or_field_name']) # instead of self.request.GET or self.request.POST
return obj
Related
I am trying to delete a record after displaying it with DetailView and redirecting to the list page again.
view.py
...
class DailyRecordDeleteConformationView(RequiredBasicDetailsAndContextMixin, DetailView):
model = DailyRecord
obj_not_found_redirect = reverse_lazy('business:add_daily_records')
template_name = 'business/daily_records_detail.html'
context_object_name = 'record'
def get_object(self):
detail = self.model.custom_obj.get_single(self)
return detail
class DailyRecordDeleteView(RequiredBasicDetailsMixin, RedirectView):
pattern_name = 'business:daily_records'
def get_redirect_url(self, *args, **kwargs):
# Delete the record
return super().get_redirect_url(*args, **kwargs)
...
urls.py
...
path('daily-records/', DailyRecordView.as_view(), name='daily_records'),
path('daily-records/<int:pk>/', DailyRecordDeleteConformationView.as_view(), name='daily_record_detail'),
path('daily-records/<int:pk>/delete/', DailyRecordDeleteView.as_view(), name='daily_record_delete'),
...
Here I am getting this below error when click on the delete button on detail view
NoReverseMatch at /business/daily-records/7/delete/
Reverse for 'daily_records' with keyword arguments '{'pk': 7}' not found. 1 pattern(s) tried: ['business/daily\\-records/\\Z']
I am new to class based views, and still not able to figure out how to redirect to url that does not have the pk parameter.
I tryed to find any variable for RedirectView or something that can skip the pk of current url while redirecting to another url.
Thanks.
When you invoke get_redirect_url with **kwargs, your pk is in kwargs and in RedirectView, Django tries to get your url with that kwargs.
So if you don't want to pass the pk, just don't pass kawrgs:
def get_redirect_url(self, *args, **kwargs):
return super().get_redirect_url()
You can specify url instead of pattern_name, so:
from django.urls import reverse_lazy
class DailyRecordDeleteView(RequiredBasicDetailsMixin, RedirectView):
urls = reverse_lazy('business:daily_records')
# no get_redirect_url
Your get_redirect_url is also not supposed to delete records: the HTTP protocol specifies that GET and OPTION should be "safe" methods, that means they should not have side-effects.
You thus should delete records with a POST/DELETE request. You can work with a small FormView that will tackle this in case the (empty) form is valid, so by overriding the form_valid method.
Well, actually the question is in the title :)
I want to have an UpdateView with different redirects depending on the referer from which the update is called.
Update: Initially, my question was misleading. I did not only want to access the meta data, but especially the http_referer of the site which led to the updateview.
It really depends on a view. If you use generic CBV you should call self.request.meta more info here. But if you just extend the View class you can do it like in the docs namely
from django.http import HttpResponse
from django.views import View
class MyView(View):
def get(self, request):
# <view logic>
request.meta
return HttpResponse('result')
I solved it by using
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['ref'] = self.request.META['HTTP_REFERER']
return context
def get_success_url(self):
if 'uebersichteingaben_nichtabgeschlossen' in self.request.POST['ref']:
return reverse_lazy(url_app_name + 'uebersichteingaben_nichtabgeschlossen')
else:
return reverse_lazy(url_app_name + 'uebersichteingaben_alle')
in the CBV. And I used the context['ref'] as hidden input in the template.
Here is my views for DRF API
class CityEventsViewSet(viewsets.ModelViewSet):
def __init__(self, request, *args, **kwargs):
queryset = CityEvents.objects.filter(city=kwargs.get('city_name'))
serializer_class = CityEventsSerializer
URL:
router.register(r'cityevents/(?P<city_name>[\w\-]+)/$', CityEventsViewSet, base_name='cityevents')
I am not able to access the views function. It is not able to resolve the URL.
kwargs['city_name']
if I understand well what you mean
The url kwargs can be accessed in anywhere in the viewset as it is an instance attribute of the viewset. As a result, you don't need to do that filtering in __init__() but in the get_queryset() method.
Something like this should suffice:
def get_queryset(self):
city_name = self.kwargs['city_name']
queryset = CityEvents.filter(city_name=city_name)
return queryset
This fix worked for me. The retrieve function will receive the arguments passed through the url. and we don't need to add the regex in URL
class CityEventsViewSet(viewsets.ModelViewSet):
queryset = CityEvents.objects.all()
serializer_class = CityEventsSerializer
def retrieve(self, request, pk=None):
queryset = CityEvents.objects.filter(city=pk)
return JsonResponse(CityEventsSerializer(queryset,many=True).data,safe=False)
URL :
router.register(r'cityevents', CityEventsViewSet)
I have a CreateView for a patient object (simplified):
from django.views.generic.edit import CreateView
import models
class PatientCreate(CreateView):
model = models.Patient
fields = ['name', 'country', ..]
# template_name is "patient_form.html" from CreateView
(I have overridden form_valid and get_context_data to set a few things by default, see for example here, but I think that's irrelevant.)
If a patient by the same name already exists, I'd like to simply HTTP forward to the detail page for that patient instead of creating a new one.
How do I do that?
I'm using Django 1.11.
You can add this logic in form_valid override. For example:
def form_valid(self, form):
name = form.cleaned_data.get('name')
your_model_objects = YourModel.objects.filter(name=name)
if your_model_objects.exists(): # lazy query, won't hit the database
obj = your_model_objects.first() # as entry exists, fetch the first object
return redirect(reverse('detail-url', args=[obj.pk])
else:
return super(YourClass, self).form_valid(form)
I have a DetailView in django views.py where I want to be able to compare the pk value from the url ex:localhost:8000/myapp/details/3/ and the request.user.id with an if statement.
There is nothing more than the following few lines of code in the view:
class UserDetail(DetailView):
model = Profile
template_name = 'details.html'
Any help would be much appreciated.
Inside a DetailView you have access to self.request, self.args and self.kwargs!
ref.: https://docs.djangoproject.com/en/dev/topics/class-based-views/generic-display/#dynamic-filtering
In your urls.py add something like this:
urlpatterns = [
#...
url(r'^details/(?P<pk>[0-9]+)/$', UserDetail.as_view()),
]
and your UserDetail can now access request.user.id and pk by self.kwargs['pk'] (see reference above: kwargs is name-based, so that you can access it by self.kwargs['name'] and self.args is position-based, so you would access it by self.args[0]).
If I understand your problem correctly, you are trying to manipulate the queryset of the DetailView, to only return the data if the current logged in user is trying to access his page.
If this is true, then you should override get_queryset in your class, like that:
def get_queryset(self):
if self.kwargs['pk'] == self.request.user.id:
return Profile.objects.filter(id=self.request.user.id)
else:
return Profile.objects.none()