Reputation: 103
I am trying to create a very simple custom view for my application. Lets imagine I have a simply model:
class Person(models.Model):
Name = models.CharField(max_length = 255)
pass
class Company(models.Model):
Title = models.CharField(max_length = 255)
pass
I would like to display a list of objects. On one url - list of person, on another - list of companies. So I create simply views:
def PersonListView (request):
_persons = Person.objects.all()
context = {
"object_list": _persons
}
return render (request, "PersonListView.html", context)
def CompanyListView (request):
_companies = Person.objects.all()
context = {
"object_list": _companies
}
return render (request, "CompanyListView.html", context)
Then add path to urls - /Person for list of persons and /Company for list of companies.
urlpatterns = [
path('/Person', PersonListView),
path('/Company', CompanyListView)
]
All working well. But I already have a questions:
Why my view function have a request variable, but I can call this function from urls without defining this variable?
Why I can't use this syntax path('/Person', PersonListView())
? What is wrong with this brackets?
And another part of my question. But then I decided to make some refactoring - I intended to use one view both for person and companies, so I have to pass a variable context to view function. And I basically know how to do it:
def ObjectList (request, _context):
_objects = _context.objects.all()
data = {
"object_list": _objects
}
return render (request, "ListView.html", data)
Here _context - concrete class (Person or Company).
My problem is in urls.py I have to call ObjectList and pass 2 variables:
_context - there is no problem here, I know how to do it
and request.
Here I faced a wall, because I don't understand how can I pass it to my function. If I just let it empty, I have an error "ObjectList() missing 1 required positional argument: 'request'"
Here is the traceback:
Internal Server Error: /Entities/Person/
Traceback (most recent call last):
File "D:\Work\Python\virtualenvs\TestProject\lib\site-packages\django\core\handlers\exception.py", line 34, in inner
response = get_response(request)
File "D:\Work\Python\virtualenvs\TestProject\lib\site-packages\django\core\handlers\base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "D:\Work\Python\virtualenvs\TestProject\lib\site-packages\django\core\handlers\base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
TypeError: ObjectList() got multiple values for argument '_context'
[25/Jul/2019 00:25:37] "GET /Entities/Person/ HTTP/1.1" 500 62910
Upvotes: 0
Views: 329
Reputation: 599630
Your second question answers your first. You don't call the view from the URL; Django does that internally when it encounters a matching request. If you try to call it from there, then you get the error you see.
I don't understand though why you think you need to pass request from the URL in the third question. You don't, that's the whole point of your questions 1 and 2.
Your URL pattern should either capture the arguments for the view, or pass them as the third parameter to path
. So, in your case, you could use a single pattern which captures the variable:
path('/<str:object_type>/', object_list, name='object_list')
and then:
def object_list(request, object_type):
types = {'Person': models.Person, 'Company': models.Company}
if object_type not in types:
raise Http404
objects = types[object_type].objects.all()
Alternatively, use two separate URL patterns and pass the type as the third parameter explicitly:
urlpatterns = [
path('/Person', object_list_view, {'object_type': Person}, name='person_list'),
path('/Company', object_list_view, {'object_type': Company}, name='company_list'),
]
and your view can be:
def object_list(request, object_type):
objects = object_type.objects.all()
Finally, though, for this very simple use case you should consider using a generic list view; then you wouldn't need to define any views at all:
from django.views.generic import ListView
urlpatterns = [
path('/Person', ListView.as_view(model=Person)),
path('/Company', ListView.as_view(model=Company))
]
Upvotes: 1