Proxy Model Customization

I have proxy models for related types. The problem is ListView and DetailView connection.

Courses has all types of course, each course must have related type’s URL.

Here is full structure of my sample code, ( models, views, urls, template)

#models.py
COURSE_TYPES = (
    ('a', 'Appetizer'),
    ('s', 'Soup and Salad'),
    ('m', 'Main Course'),
    ('d', 'Dessert')
)


class Course(models.Model):
    type = models.CharField(max_length=1, choices=COURSE_TYPES)
    name = models.CharField(max_length=100)
    slug = models.SlugField(blank=True, unique=True)
    thumbnail = models.ImageField(null=True, blank=True)
    description = models.TextField(max_length=1000)

    def get_absolute_url(self):
        return reverse('course', kwargs={'slug':self.slug})
         
class AppetizerManager(models.Manager):
    def get_queryset(self):
        return super(AppetizerManager, self).get_queryset().filter(
            type='a')
      
class MainManager(models.Manager):
    def get_queryset(self):
        return super(MainManager, self).get_queryset().filter(
            type='m')
      
class Appetizer(Course):
    objects = AppetizerManager()
    class Meta:
        proxy = True  
        
class Main(Course):
    objects = MainManager()
    class Meta:
        proxy = True
        

#views.py
class CourseListView(ListView):
    model = Course
    template_name = 'courses.html'
    
class AppetizerDetailView(DetailView):
    model = Appetizer
    template_name = 'appetizer_detail.html'

class MainDetailView(DetailView):
    model = Main
    template_name = 'main_detail.html'

    
#urls.py
urlpatterns = [
    path('courses/', views.CourseListView.as_view(), name='courses'),
    path('appetizer/<slug:slug>/', views.AppetizerDetailView.as_view(), name='appetizer'),
    path('main/<slug:slug>/', views.MainDetailView.as_view(), name='main'),
    ]


#courses.html
<h1>Courses</h1>
{% for course in object_list %}
  <ul>
    <li><a href="{{ course.get_absolute_url }}">{{ course.name }}</a></li>
  </ul>
{% endfor %}

How can I edit my code for this purpose properly?

Thanks.

Can you be more specific and provide more detail about the problems you’re having? What isn’t working? What are you trying to do that isn’t working?

@KenWhitesell, thanks for your feedback.

As you see, parent class has a function that generate URL for each course objects.

#models.py
class Course(models.Model):
	# ...
	def get_absolute_url(self):
		return reverse('course', kwargs={'slug':self.slug})

#views.py
class CourseListView(ListView):
    model = Course
    template_name = 'courses.html'

#courses.html
{% for course in object_list %}
  <ul>
    <li><a href="{{ course.get_absolute_url }}">{{ course.name }}</a></li>
  </ul>

After I create proxy model, I try to override get_absolute_url on the each proxy model.

#models.py
class Appetizer(Course):
    # ...
    def get_absolute_url(self):
        return reverse('appetizer', kwargs={'slug':self.slug})        

class Main(Course):
    # ...
    def get_absolute_url(self):
        return reverse('main', kwargs={'slug':self.slug})

Because each type of courses should have different URL.

#urls.py
urlpatterns = [
    path('courses/', views.CourseListView.as_view(), name='courses'),
    path('appetizer/<slug:slug>/', views.AppetizerDetailView.as_view(), name='appetizer'),
    path('main/<slug:slug>/', views.MainDetailView.as_view(), name='main'),
    ]

The problem is I can not use proxy models’ generated URL in the courses list to pass proxy model detail pages.

I hope it was clearer.

Thanks in advance.

Yes, thanks. From the docs: Querysets still return the model that was requested. So your query isn’t going to work the way you would like. There may be an easier way to accomplish what you want other than aggregating individual queries on each subtype, but if there is, it’s not coming to mind at the moment. (Admittedly, I’ve done very little work with proxy models, so I don’t have much experience to draw from.) I guess you could customize your get_absolute_url method to test which type of Course the current instance is and call reverse based on that.

The ‘get_absolute_url’ method is customized.

class Course(models.Model):
    # ...
    def get_absolute_url(self):        
        if self.type == 'a':
           viewname = "appetizer"
        elif self.type == 'm':
           viewname = "main"
        # ...
        return reverse(viewname, kwargs={'slug':self.slug})

It works as I expect.
If I have better solution, I’ll share here. Maybe it helps for similar situations to others.