daevaorn / djapian

High level Xapian integration for Django
Other
6 stars 3 forks source link

Add way to figure out the model in the template for composite searches and linking to the results #114

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
Currently there is no "easy" way to figure out the model for the hit in the 
template. 
hit.model returns the model object, not the class for it.

Original issue reported on code.google.com by hvdkl...@gmail.com on 11 Jun 2010 at 11:51

GoogleCodeExporter commented 9 years ago
Having a `hit.model' object one could use generic Python introspection:

    from <project>.<application>.models import MyModel, MyAnotherModel
    ...

    indexers = [MyModel.indexer, MyAnotherModel.indexer]
    indexer CompositeIndexer(*indexers)
    for hit in indexer.search("search terms"):
        if isinstance(hit.model, MyModel):
            # do something
    ...

There's also Django's Options class instance `hit.model._meta` which has 
`app_label` and `db_table` attributes among others (see 
http://docs.djangoproject.com/en/dev/ref/models/options/#available-meta-options)

Original comment by esizi...@gmail.com on 21 Jun 2010 at 3:09

GoogleCodeExporter commented 9 years ago

Original comment by daevaorn on 21 Jun 2010 at 3:43

GoogleCodeExporter commented 9 years ago
You're not allowed to access _ attributes in the template.
And looping through everything twice doesn't make sense.

Now I'm searching users and forum posts. The results should link to totally 
different things. get_absolute_url is nice but kinda evil and unusable for the 
forum posts.

so I just want to be able to check the app_name and model_name without having 
to write a whole templatetag for it. Either add them as properties to the hit 
class or add a template tag to get them from a hit.

Original comment by hvdkl...@gmail.com on 22 Jun 2010 at 11:56

GoogleCodeExporter commented 9 years ago
I think we add `model_name` attribute to hit object.`````

Original comment by daevaorn on 22 Jun 2010 at 12:36

GoogleCodeExporter commented 9 years ago
I'll be needing this pretty soon for a big project. If it's not in by then I'll 
probably write a patch myself. If I do I'll post it here.

Original comment by hvdkl...@gmail.com on 23 Jun 2010 at 8:49

GoogleCodeExporter commented 9 years ago
I would suggest to go with a templatetag.

How do you usually get a `model_name` for a standard Django QuerySet results 
item?

Original comment by esizi...@gmail.com on 24 Jun 2010 at 7:18

GoogleCodeExporter commented 9 years ago
What I did now to quickly overcome the problem is this:

@register.filter
def get_model_from_hit(hit):
  """
    Returns the `app_label.model_name` for the hit
  """
  content_type = ContentType.objects.get_for_model(hit.model)
  return "%s.%s" % (content_type.app_label, content_type.model)

Original comment by hvdkl...@gmail.com on 24 Jun 2010 at 7:29

GoogleCodeExporter commented 9 years ago
Having a filter is exactly the stadard way how to get Django model's options ;)

I would not use ContentType here as it will make addition hit into the database.
Please consider the code below.

from django import template
from django.template.defaultfilters import stringfilter

register = template.Library()

@register.filter
@stringfilter
def get_model_from_hit(hit):
  """
    Returns the `app_label.model_name` for the hit
  """
  opts = hit.model._meta
  return "%s.%s" % (opts.app_label, opts.module_name) # there is also opts.object_name which is the exact model's class name like `MyCoolModel`
get_model_from_hit.is_safe = True

Original comment by esizi...@gmail.com on 24 Jun 2010 at 7:45

GoogleCodeExporter commented 9 years ago
ContentTypes are cached.. as long as the server is running it hits the database 
only once ;-)

But yeah.. your method would be better :)

Original comment by hvdkl...@gmail.com on 24 Jun 2010 at 7:57

GoogleCodeExporter commented 9 years ago
Oh.. and you don't want the string filter thing. It converts all the input to 
unicode, which the hit isn't :)

Original comment by hvdkl...@gmail.com on 24 Jun 2010 at 7:59

GoogleCodeExporter commented 9 years ago
Yep, @stringfilter is not need here - I copy-pasted the decorators from another 
filter ;)

Original comment by esizi...@gmail.com on 24 Jun 2010 at 8:02

GoogleCodeExporter commented 9 years ago
So the final version is:

from django import template

register = template.Library()

@register.filter
def get_model_from_hit(hit):
  """
    Returns the `app_label.model_name` for the hit
  """
  opts = hit.model._meta
  return "%s.%s" % (opts.app_label, opts.module_name)
get_model_from_hit.is_safe = True

Original comment by esizi...@gmail.com on 24 Jun 2010 at 8:13

GoogleCodeExporter commented 9 years ago
I think this filter can be more generalized (accepts model itself not `hit` 
instance) and ships separately.

Close ticket?

Original comment by daevaorn on 24 Jun 2010 at 12:54

GoogleCodeExporter commented 9 years ago
I'd vote for not making this a part of Djapian, and closing the issue as 
"WontFix"

Original comment by esizi...@gmail.com on 25 Jun 2010 at 5:30

GoogleCodeExporter commented 9 years ago
I think it should be part of djapian. You will need this in every 
CompositeIndex template because you otherwise don't know where to link the 
result to.

Original comment by hvdkl...@gmail.com on 25 Jun 2010 at 6:38

GoogleCodeExporter commented 9 years ago
The usage of search results is an application domain. The filter above is just 
an example. Having a "app_label.model_name" string wouldn't help a lot for 
"linking". You could use {{{hit.instance.get_get_absolute_url}}} in your 
template to get a public link to the result hit instance whatever "type" it has.

Original comment by esizi...@gmail.com on 30 Jun 2010 at 6:25