0

I was searching this for a while and did not figure out anyway. Let's say we have a models.py with 3 models dogs, cats and birds. In url.py we want to have a single line that works with generic ListView and DetailView for each model type. Our views.py is dynamic and accepts models from url.py.

smth for eaxmple:

from django.urls import path
from django.views.generic import TemplateView
from . import views
from . import models
urlpatterns = [
    path('animals/<???>/', views.AnimalList.as_view(template_name = 'animals.html', model = ???), name='lots'),
]

so when we go to .../animals/dogs, it loads data from dogs, or when we go to .../animals/cats we get data from cats table, and so on. How do we do this?

p.s. I have the working views.py based on generic so I am not sharing it here :)

Gevorg Hakobyan
  • 328
  • 3
  • 14
  • Have you seen [this](https://stackoverflow.com/questions/31474328/django-url-to-dynamic-model-loading) SO post which seems to deal with a similar question? – Chris Feb 02 '20 at 21:09
  • hi Chris, thanks, I have seen it, but I already implemented a view that accepts any model passed to it. my problem is related to url configuaration and passing models from urls.py views.AnimalList.as_view(model = {dynamically put models here}). – Gevorg Hakobyan Feb 02 '20 at 21:14

2 Answers2

1

Perhaps this will work for your needs with using inspect module:

import sys, inspect

from django.db.models import Model
from django.urls import path
from django.views.generic import TemplateView
from . import views
from . import models

# find classes in models.py
is_class_member = lambda member: inspect.isclass(member)
class_members = inspect.getmembers(sys.modules['your_app_name.models'], is_class_member)

urlpatterns = [
path(f'animals/{item[0]}/', views.AnimalList.as_view(template_name = 'animals.html', model = item[1]), name='lots') for item in class_members]

You may need to fill your_app_name or find the proper name in namespace. Also, you may want some more filtering options to be applied to models search - just extend lambda by adding and/or conditions.

Charnel
  • 4,222
  • 2
  • 16
  • 28
  • Pretty nice and seems what I need. I will get back with feedback. as I understand, it automatically assigns members and does not require assigning model for lambda like is_class_member(models)? – Gevorg Hakobyan Feb 02 '20 at 21:36
  • 1
    Yes, exact. The only slippery thing here is `sys.modules['your_app_name.models']`. I checked it working for absolute import in a way I wrote it, but for relative import you may need to check `modules` keys to find the proper one for your models file. – Charnel Feb 02 '20 at 21:47
  • perfect solution! – Gevorg Hakobyan Feb 05 '20 at 09:04
0

I would start by creating a views function that accepts the request and animal type header. The function will look up the data based on the header and then render the template. Something like this:

# urls.py:

urlpatterns = [
    path('animals/<???>/', views.GetAnimalData, name='lots'),
]


# views.py:

def GetAnimalData(request, animal):

    # 1) look up animal data in database:
    if animal == 'Dog':
        animal_data = Dog.objects.get() # specify query set here
    elif animal == 'Cat':
        animal_data = Cat.objects.get()
    elif ...

    # 2) pack data into context:
    context = {
        'name' : animal_data.name,
        'color' : animal_data.color, 
        ...
    }

    # 3) render template with context:
    return render(request, 'animals.html', context=context)

Let me know if you need more details.

Daniel
  • 3,228
  • 1
  • 7
  • 23
  • nah, Daniel. that is not what I want. if we have large list of animals, writing if statements for each one is not practical. I have dynamic views based on generic class. they accept the model from urls.py. I want to be able to write inside urls.py a way, so it passes the string in the url ??? as the name of the model. so when we visit .../animals/dogs, the views.AnimalList.as_view(template_name = 'animals.html', model = ???) the ??? becomes dogs, so my views.py getd data from dogs, when we go to cats, it does the same for cats, and so on, for as many models as we might want. – Gevorg Hakobyan Feb 02 '20 at 21:05
  • My apologies - have you tried extending the default ListView class to include the extra parameter? – Daniel Feb 02 '20 at 21:11