2

Im trying to access the detailpage of a photo instance, but I can't seem to get it to work. (The category detail page works great!)

I would like to access http//domain.com/main-category/sub-cat/sub-sub-cat/photo-slug/

Models.py:

from mptt.models import MPTTModel, TreeForeignKey


class Category(MPTTModel):
    name = models.CharField('category name', max_length=32)
    parent = TreeForeignKey('self', null=True, blank=True, verbose_name='parent category', related_name='categories')
    slug = models.SlugField(unique=True)

    def get_absolute_url(self):
        return reverse('gallery', kwargs={'path': self.get_path()})


class Photo(models.Model):
    name = models.CharField('photo name', max_length=32)
    parent = TreeForeignKey(Category, verbose_name='parent category', related_name='photos')
    slug = models.SlugField()

    class Meta:
        unique_together = ('slug', 'parent')

urls.py:

url(r'^(?P<path>.*)', mptt_urls.view(model='gallery.models.Category', view='gallery.views.category', slug_field='slug'), name='gallery'),

views.py:

def category(request, path, instance):
    return render(
        request,
        'gallery/category.html',
        {
            'instance': instance,
            'children': instance.get_children() if instance else Category.objects.root_nodes(),
        }
    )

How is it possible to access the photo model using mtpp-urls ?

Edit 1:

Sorry, when I try a url like http//domain.com/main-category/sub-cat/sub-sub-cat/photo-slug The template display the Gallery main page because there is no instance when I try the url with the photo-slug (and yes, the photo has the category as a parent :)

Here is the category.html template:

<html>
    <head>
        <title>{% if instance %}{{ instance.name }}{% else %}Gallery main page{% endif %}</title>
    </head>
    <body>
        <h3>{% if instance %}{{ instance.name }}{% else %}Gallery main page{% endif %}</h3>

        <a href="{% url 'gallery' path='' %}">Gallery main page</a>
        {% for ancestor in instance.get_ancestors %}
            > <a href="{{ ancestor.get_absolute_url }}">{{ ancestor.name }}</a>
        {% endfor %}
        > <strong>{{ instance.name }}</strong>

        <h4>Subcategories:</h4>
        <ul>
            {% for child in children %}
                <li><a href="{{ child.get_absolute_url }}">{{ child.name }}</a></li>
            {% empty %}
                <li>No items</li>
            {% endfor %}
        </ul>

        <h4>Photos:</h4>
        <ul>
            {% for object in instance.photos.all %}
                <li><a href="{{ object.slug }}">{{ object.name }}</a></li>
            {% empty %}
                <li>No items</li>
            {% endfor %}
        </ul>        
                
    </body>
</html>
Community
  • 1
  • 1
Tomas Jacobsen
  • 2,368
  • 6
  • 37
  • 81

1 Answers1

1

The reason why it doesn't work is that MPTT only works on one model at a time, in that case the gallery, not the photo.

So actually, in your models the Gallery is NOT the parent of the photo, but just a foreign key on the photo.

If you know that the last element of the slug is always a photo, you could probably create an intermediate view like this:

urls.py:

url(r'^(?P<path>.*)', views.photo, name='photo'),

views.py:

def photo(self, path=''):
    path_parts = path.split('/')
    gallery_path = '/'.join(path_parts[:-1])
    photo_slug = path_parts[-1]
    return mptt_urls.view(model='gallery.models.Category', view='gallery.views.photo_in_category', slug_field='slug')({'path': gallery_path, 'photo_slug': photo_slug})

def photo_in_category(request, path, gallery_instance, photo_slug=None):
    photo_instance = Photo.objects.get(parent=gallery_instance, slug=photo_slug)
    ...

Otherwise, you may need to differentiate the URLS (which would also bring simpler code):

urls.py:

url(r'^photo/(?P<path>.*)/(?P<photo_slug>[-\w]+)/$', mptt_urls.view(model='gallery.models.Category', view='gallery.views.photo_in_category', slug_field='slug'), name='photo'),
url(r'^gallery/(?P<path>.*)/$', mptt_urls.view(model='gallery.models.Category', view='gallery.views.category', slug_field='slug'), name='gallery'),
raphv
  • 1,153
  • 7
  • 10
  • When I try this method, the view is complaining about not getting a `path` as keyword argument. Tried hardcoding the path like this `category1/category2/` but got the same error `'Path was not captured! Please capture it in your urlconf. Example: url(r\'^gallery/(?P.*` – Tomas Jacobsen Jun 29 '16 at 07:26
  • Sorry, I've realised there was a typo in my answer. Can you retry it now? – raphv Jun 29 '16 at 10:46
  • Does not seem to work, now nothing is able to reverse. I want a url pattern that could handle urls like `main-category/` and `main-category/sub-category/` and `main-category/sub-category/article/` and also `main-category/article/` I don't want to have `photo` and `gallery` in front of each url based on if it is a gallery or a photo. Is it not possible? – Tomas Jacobsen Jun 29 '16 at 12:22
  • Your current models don't prevent collisions between sub category names and photo name, which means that if you have a photo named `sunset` in category `landscape` and a subcategory also named `sunset` in `landscape`, how would you resolve `lanscape/sunset`? – raphv Jun 29 '16 at 13:51