开发者

Handling related models in Django for use in Django-Piston

开发者 https://www.devze.com 2023-01-16 06:03 出处:网络
I have setup like so (changed for simplicity) class Author(models.Model) name = models.CharField(max_length=100)

I have setup like so (changed for simplicity)

class Author(models.Model)
    name = models.CharField(max_length=100)
    ...

class Document(models.Model):
    title = models.CharField(max_length=200)
    content - models.TextField()
    author = models.ForeignKey("Author", related_name="documents")
    date_published = models.DateTimeField()
    categories = models.ManyToManyField("Category")

class Category(models.Model):
    name = models.CharField(max_length=100)

I'm pulling in the Author records but I only want to pull in related document records for each author that match specific criteria -- say, date_published and category.

I know the easy way to do this would be to pull in the records as a list of dictionaries using Author.objects.values(), looping through each record and running:

author['documents']=Document.objects.filter(categories__in=[category_list], date_published__year=year)`

However, this is be开发者_JAVA技巧ing generated for django-piston, and it seems to be happiest (particularly if you're defining your own fields!) if you return a QuerySet object.

Part of this may be because I made changes to the base django-piston code. Basically, the current version of the code here overwrites the fields value. I changed this code so that I could change the fields value for a Handler based on the request (so I could provide more details if the request was for a specific resource).

So I guess my question is three-fold:

  1. Is there a way to filter or somehow limit the subrecords of a record (i.e. filter documents for each author.documents)
  2. If not, what is a functional way of doing this that also works with django-piston?
  3. Is there some easier, better way to do what I'm trying to do (display all the authors without their documents if an id is not given, but displaying the sub-records if filtering to just one author)?

Clarification

Okay, just to be clear, here is the pseudocode that I want:

def perhaps_impossible_view(request, categories=None, year=None):
    authors = Author.objects.all()
    authors.something_magical_happens_to_documents(category__in=[categories], date_published__year=year)
    return render_to_response('blar.html', locals(), RequestContext(request))

So that if I were to put it in a template, this would work without any modifications:

{% for a in authors %}
    {% for d in authors.documents.all %}
        {{ d.title }} is almost certainly in one of these categories: {{ categories }} and was absolutely published in {{ year }}. If not, .something_magical_happens_to_documents didn't work.
    {% endfor %}
{% endfor %}

something_magical_happens_to_documents has to run and actually change the contents of documents for each author record. It seems like this should be possible, but perhaps it isn't?


Edited... or better... replaced! :)

That's true the authors without document matching won't be in the queryset so you will have to add them back after (I couldn't find a better way but maybe someone knows how to not remove them without using raw sql).

You get the full documents count of the authors because you don't use the queryset to get the document counts:

qryset = Author.objects.all()
qryset = qryset.filter(documents__categories__name__in = category_list).distinct()
qryset = qryset.filter(documents__date_published__year=year)

print(qryset) gives [<Author: Author object>] (if only 1 author matched all categories) and qryset[0].documents.count() will return only the number of documents matched (not all documents from the author - 2 in the case I tested and the author had 4 but only 2 matching all conditions).

If you use dict (.values()) instead of querysets in the steps above, you can't do that (I think) because dict won't have a documents field so:

qryset_dict = Author.objects.values()
qryset_dict = qryset_dict.filter(documents__categories__name__in = category_list).distinct().values()
qryset_dict = qryset_dict.filter(documents__date_published__year=year).values()

when you issue qryset_dict[0].documents.count() you receive an error:

AttributeError: 'dict' object has no attribute 'documents'


Now to add the filtered authors back you can do:

res = []
for a in Author.objects.all():
    if a in qryset:
        res.append([a,a.documents.count()])
    else:
        res.append([a,0])

and res will be a list with <authors> in 1st column and count of documents matching in 2nd column.

I know this is far from perfect... but if you are interested only in the count() of matching documents per author, I think you could find a better way using django aggregation and annotation or possibly make it with raw sql using a left join from authors to documents.




EDIT after Clarification in Question:

def possible_view(request, categories=None, year=None):
    # you will pass these as parmeters of course
    category_list = ['c2', 'c3']
    year = 2010

    qryset = Document.objects.filter(categories__name__in = category_list).distinct()
    qryset = qryset.filter(date_published__year=year)
    authors = Author.objects.all()
    return render_to_response('blar.html', { 'result': qryset, 'authors': authors, 'categories': category_list, 'year': year }, RequestContext(request))

Template blar.html:

{% for a in authors %}
    <b>{{a.name}}</b><br />
    {% for d in result %}
        {% if d.author.name == a.name %}
            {{ d.title }} is almost certainly in one of these categories: {{ categories }} and was absolutely published in {{ year }}. If not, .something_magical_happens_to_documents didn't work.<br />
        {% endif %}
    {% endfor %}<br />
{% endfor %}

This will give you something not very pretty but with all authors and below each one, the list of their documents that fall within one of the category_list (OR condition, for AND, you need to filter the query for each category instead of using __in).

If the author has no document in the category_list, it wil be listed without documents below him.


Something like:

aut1
tit2 is almost certainly in one of these categories: ['c2', 'c3'] and was absolutely   published in 2010. If not, .something_magical_happens_to_documents didn't work.
tit1 is almost certainly in one of these categories: ['c2', 'c3'] and was absolutely published in 2010. If not, .something_magical_happens_to_documents didn't work.

aut2
tit3 is almost certainly in one of these categories: ['c2', 'c3'] and was absolutely published in 2010. If not, .something_magical_happens_to_documents didn't work.

aut3
0

精彩评论

暂无评论...
验证码 换一张
取 消