문제

I don't really understand get_comment_permalink in Django's comments framework.

I created a few comments for my class Order using Django's comments, by default it shows a url of something like /comments/cr/18/1/#c1 and that url never exists.

I looked at the comment's urls.py and it has a line that says

urlpatterns += patterns('',
    url(r'^cr/(\d+)/(.+)/$', 'django.contrib.contenttypes.views.shortcut', name='comments-url-redirect'),
)

The views.py which has the shortcut method is

from django import http
from django.contrib.contenttypes.models import ContentType
from django.contrib.sites.models import Site, get_current_site
from django.core.exceptions import ObjectDoesNotExist
from django.utils.translation import ugettext as _

def shortcut(request, content_type_id, object_id):
    """
    Redirect to an object's page based on a content-type ID and an object ID.
    """
    # Look up the object, making sure it's got a get_absolute_url() function.
    try:
        content_type = ContentType.objects.get(pk=content_type_id)
        if not content_type.model_class():
            raise http.Http404(_(u"Content type %(ct_id)s object has no associated model") %
                               {'ct_id': content_type_id})
        obj = content_type.get_object_for_this_type(pk=object_id)
    except (ObjectDoesNotExist, ValueError):
        raise http.Http404(_(u"Content type %(ct_id)s object %(obj_id)s doesn't exist") %
                           {'ct_id': content_type_id, 'obj_id': object_id})

    try:
        get_absolute_url = obj.get_absolute_url
    except AttributeError:
        raise http.Http404(_("%(ct_name)s objects don't have a get_absolute_url() method") %
                           {'ct_name': content_type.name})
    absurl = get_absolute_url()

    # Try to figure out the object's domain, so we can do a cross-site redirect
    # if necessary.

    # If the object actually defines a domain, we're done.
    if absurl.startswith('http://') or absurl.startswith('https://'):
        return http.HttpResponseRedirect(absurl)

    # Otherwise, we need to introspect the object's relationships for a
    # relation to the Site object
    object_domain = None

    if Site._meta.installed:
        opts = obj._meta

        # First, look for an many-to-many relationship to Site.
        for field in opts.many_to_many:
            if field.rel.to is Site:
                try:
                    # Caveat: In the case of multiple related Sites, this just
                    # selects the *first* one, which is arbitrary.
                    object_domain = getattr(obj, field.name).all()[0].domain
                except IndexError:
                    pass
                if object_domain is not None:
                    break

        # Next, look for a many-to-one relationship to Site.
        if object_domain is None:
            for field in obj._meta.fields:
                if field.rel and field.rel.to is Site:
                    try:
                        object_domain = getattr(obj, field.name).domain
                    except Site.DoesNotExist:
                        pass
                    if object_domain is not None:
                        break

    # Fall back to the current site (if possible).
    if object_domain is None:
        try:
            object_domain = get_current_site(request).domain
        except Site.DoesNotExist:
            pass

    # If all that malarkey found an object domain, use it. Otherwise, fall back
    # to whatever get_absolute_url() returned.
    if object_domain is not None:
        protocol = request.is_secure() and 'https' or 'http'
        return http.HttpResponseRedirect('%s://%s%s'
                                         % (protocol, object_domain, absurl))
    else:
        return http.HttpResponseRedirect(absurl)

and it's too complicated for me to understand.

When Django says permalink, I think about having a reference to a particular place on a page (usually a header). For example, the Django's comments framework documentation is link #1, and you can permalink the "Linking to Comments" section with link #2.

1. https://docs.djangoproject.com/en/dev/ref/contrib/comments/
2. https://docs.djangoproject.com/en/dev/ref/contrib/comments/#linking-to-comments

So for the comments, shouldn't it be the same? Shouldn't the URL simply be a #c1 or something without the /comments/cr/18/1/...? In fact I don't even know where Django got 18 and 1... From the shortcut method, I understand that 18 is the content_type_id and 1 is the object_id, but how can I tell which class in models.py is which content type id and object id?

도움이 되었습니까?

해결책

So for the comments, shouldn't it be the same? Shouldn't the URL simply be a #c1 or something without the /comments/cr/18/1/...? In fact I don't even know where Django got 18 and 1... From the shortcut method, I understand that 18 is the content_type_id and 1 is the

18 is the content type id, and 1 is the object id. The shortcut view fetches the object from the database using these parameters and redirects to modelobject.get_absolute_url().

Define/fix get_absolute_url() method in your models, this will repair django.contrib.contenttypes.views.shortcut.

That said, it is expected by Django that the url of the model object displays the list of comments for this object. In that case, just add <a name="c{{ comment.id }}"></a> in your single comment HTML.

다른 팁

The comments framework uses Generic Relations to link Comment objects to your database objects (Order model in your case). Generic relationships allow one object to maintain a relationship with another object without explicitly knowing about it's class. You can see the fields creating the generic relationship (content_type, object_pk, content_object) for comment here: django.contrib.comments.models

Once a comment has been made and attached to an instance of a particular class (a single Order for example), we need a way to get a link to that particular comment (the permalink). To get a link to a comment, we need to know the URL of the object the comment has been made on (again, the particular Order in your case). This is what get_comment_permalink is doing - it constructs a URL to the object for which a comment has been left on and also attached an anchor link (the #c1 part) to the URL so that the browser jumps to a particular comment on that page.

To do all this it has 3 steps:

  • first figure out what type of object it's dealing with by looking up the generic relationship. This will leave us with a Order object
  • Now it tries to get the absolute url get_absolute_url of that object. This might be /order/my-order/
  • It constructs that `http://mysite.com/' part of the URL by using the Sites framework
  • It figures out the #c31 (anchor link to the comment) part of the url

Now we have a full http://mysite.com/order/my-order/c#31 that will bring us to the correct page and show the correct comment

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top