Issue on Django Url Routers - python

I an trying to make url router in Django which supports following URLs :
http://localhost:8000/location/configuration
http://localhost:8000/location/d3d710fcfc1391b0a8182239881b8bf7/configuration
url(r'^locations/configuration$',
location_config.as_view(), name="location-config"),
url(r'^locations/(?P<location_key>[\w]+)/configuration$',
location_config.as_view(), name="location-config-uri")
Whenever I tried to hit http://localhost:8000/location/configuration, it picked up the second URL routing format instead of picking up first one.
Error:
TypeError at /locations/configuration/ get() missing 1 required
positional argument: 'location_key'
Can anyone help me here what goes wrong with the url routing format?

Nope, it does pick the first pattern which has no arguments, however you're using the same view in both patterns and location_config view has required argument location_key which is not provided when first pattern matches the URL. That's what error message is saying.
So write another view which will not require location_key argument or alter this view definition: add default to the parameter
def location_config(request, location_key=None):
....
now it is not a "required positional argument".

django Will look for a pk when you are using a detail view by default. you have to override it by using get_object()
in your case
def get_object(self, queryset=None):
location_key = self.kwargs.get('location_key')
obj = Model.objects.get(id=location_key)
return obj

Related

Generating OpenAPI Schema in Django Rest Framework: URL Keyword in Update ViewSet

I'm trying to do something that should be pretty straight forward but I'm running into a problem that I can't make heads or tails of. I'm hoping someone can help me sort it out.
I've created some API endpoints using DRF. Naturally, I have Create, Update, Retrieve, and Delete endpoints that I've constructed with the django_rest_framework.generics. I need to send some extra data into the Serializer from the ViewSet on both the CreateAPIView and UpdateAPIView. To accomplish this, I've extended the get_serializer_context() method on those ViewSets.
I'm now trying to create OpenAPI documentation for those said endpoints. However, when I run generateschema in the manage.py it returns an error. This error occurs in each of the UpdateAPIViews where I've extended the get_serializer_context() method. An example of this error is shown below.
AssertionError: Expected view UpdateStaffViewSet to be called with a URL keyword argument named "staff_id". Fix your URL conf, or set the `.lookup_field` attribute on the view correctly.
Naturally, we'd think that I goofed the URL keyword or the lookup_field, just as the error states. Unless I'm looking over something obvious though, I just cannot see what the issue is. These endpoints function perfectly when tested using curl or postman. I do know that if I remove the extended get_serializer_context() method, the generateschema command works fine. (But then an test using postman/curl will fail.) Why in the heck would that extended method matter!?
urls.py
url_patterns = [
path('v1/staff/retrieve/<int:staff_id>/', RetrieveStaffViewSet.as_view()),
path('staff/update/<int:staff_id>/', UpdateStaffViewSet.as_view()),
...
]
viewsets
class UpdateRetrieveBase:
serializer_class = StaffSerializer
queryset = Staff.objects.select_related('user')
lookup_url_kwarg = 'staff_id'
lookup_field = 'pk'
class UpdateStaffViewSet(UpdateRetrieveBase, UpdateAPIView):
def get_serializer_context(self):
context = super().get_serializer_context()
context['validation_refs'] = get_validation_refs(staff=self.get_object())
return context
class RetrieveStaffViewSet(UpdateRetrieveBase, RetrieveAPIView):
pass
Alright well after all that, I found my own answer. I'll post it here in case someone else also gets stumped.
Since the generateschema command runs a test but then doesn't include URL kwargs, we cannot call get_object() in the viewset. The test must account for that but doesn't consider that we may be calling that method anywhere else. To fix this in my particular case I edited the code as thus.
viewset
class UpdateAEAContractViewSet(UpdateRetrieveBase, UpdateAPIView):
def get_serializer_context(self):
context = super().get_serializer_context()
contract_id = self.kwargs.get(self.lookup_url_kwarg)
context['validation_refs'] = get_validation_refs(contract_id=contract_id)
return context
validation ref subjob
def get_validation_refs(staff_id=None):
staff = Staff.objects.get(pk=staff_id) if staff_id else None
...

Pass arguments between Webapp2 redirects

I want to redirect URL without slug, to the one with slug, at the urls.py level.
My endpoints looks as follows:
(r'/invoices/<:(-?\d+)>/print/', PrintHandler, 'ShortPrintHandler')
(r'/invoices/<:(-?\d+)>/<:([\w-]*)>/print/', PrintHandler, 'FullPrintHandler')
Is there any way I can pass first, decimal, argument from short URL to the long one, on redirect? Generating URLs without slug is already covered at handler level.
Tried to handle it with
RedirectRoute(r'/invoices/<:(-?\d+)>/print/', PrintHandler, redirect_to_name='FullPrintHandler')
But an error was thrown:
KeyError: 'Missing argument "1" to build URI.'
You can't do that with just a RedirectRoute; you need to get the slug value from somewhere.
You'll need to write a standard route, and in the handler you should get the object from the datastore and return a redirect to the full path using the slug.
Something like (untested):
class RedirectToFullPath(webapp2.RequestHandler):
def get(self, invoice_id):
invoice = Invoice.get_by_id(invoice_id)
self.redirect_to('FullPrintHandler', invoice_id, invoice.slug)

Django How do i determine what arguments are missing?

Trying to access part of code by get request and receiving this error
NoReverseMatch: Reverse for 'homepage' with arguments '()' and keyword arguments '{}' not found. 0 pattern(s) tried: [] looked around for help and i think its that am missing some arguments.
here is request am using in my test
req = self.client.get('/password/reset/')
and the code it leads to is as:
class PasswordResetEmailView(FormView):
template_name = 'temp/password_reset.html'
form_class = PasswordResetForm
success_url = 'password_reset_ok'
def get(self, request, *args, **kwargs):
form = self.get_form(self.form_class)
return self.render_to_response(self.get_context_data(form=form))
any guidance ?
You ask specifically about "determining which arguments are missing", but should be irrelevant to your error.
Your error message states that it can't find any URL patterns matching the name "homepage", before attempting any argument matching. Therefore no URLs exist named "homepage" in your setup. If it was an argument mismatch, you'd see a list of named URLs in the error such as "tried X urls."
Either define a URL named home in your URLConf url(r'^home/$', 'home_view', name="homepage") or find the location that is calling reverse('homepage') and remove it. You will find this information in your traceback.

Django Redirect view with args

I have a problem with redirection in Django :
my view
def myP(request,namep):
return render(request,"site/myP.html")
def create(request):
nom="alaild"
....
return redirect(reverse(myP,namep=nom))
urls to this views
url(r'^create$', 'create', name='create'),
url(r'^myp/(?P<namep>\d+)','myP', name="myp"),
I have this error :
reverse() got an unexpected keyword argument 'name'
I want create view redirects to myP view but myP view have 1 argument and I don't know how make...
May be
reverse(myP, kwargs={'namep': nom})
In your view, nom is a string, but in your url pattern you are using \d+ (one or more digits).
A common approach is to accept a 'slug' which can contain letters, digits, underscores and hyphens:
url(r'^myp/(?P<namep>[\w-]+)','myP', name="myp"),
Then you need to fix the syntax of your reverse call. Either of the following should work.
reverse(myP, kwargs={'namep': nom})
reverse(myP, args=(nom,))

Django reverse URL issue

I'm having issues getting the following code (below) to work (there are no errors) . In my template I'm outputting item.get_settings_url but I get nothing. What I'm I doing wrong here?
In my models I have the following model method:
def get_settings_url(self):
return reverse('sms.views.keyword_settings', args=[str(self.keyword)])
urls:
url(r'^keyword/^(?P<keyword>[\.\w-]+)/settings/$', views.keyword_settings, name='keyword_settings')
view:
def keyword_settings(request, keyword):
return render_to_response('keyword_settings.html', context_instance=RequestContext(request))
Your URL contains a named parameter. Hence, you need to pass that name when calling reverse. Also, you should use the name of the URL to make the reverse lookup short and easier to maintain:
return reverse('keyword_settings', kwargs={'keyword': str(self.keyword)})

Categories