2012-06-17 14 views
5

Django के ORM का उपयोग करके प्रोग्रामिंग रूप से दो तालिकाओं में शामिल होना संभव है? मेरे पास दो मॉडल हैं: विषय और वोट। मेरे टेम्पलेट पर मेरे पास विषयों की एक सूची है जो उपयोगकर्ता Reddit जैसे वोट ऊपर/नीचे कर सकते हैं। सबकुछ काम करता है क्योंकि इसे परिणामों को सॉर्ट करने के अलावा इसे छोड़ना चाहिए। मैं यह नहीं समझ सकता कि प्रत्येक ऑब्जेक्ट की वोट गिनती के योग के आधार पर ऑब्जेक्ट्स सूची को सॉर्ट करना है। मैं किसी भी मुद्दे के बिना postgres से वांछित डेटा पुनः प्राप्त कर सकते हैं:कच्चे एसक्यूएल का उपयोग किए बिना Django का उपयोग करके आप दो तालिकाओं में कैसे शामिल हो जाते हैं?

select i.id, i.title, i.date_created, s.object_id, s.vote, Sum(vote) 
from topic_topic i, votes s 
where i.id = s.object_id 
group by 1, 2, 3, 4, 5 
order by sum DESC; 

यह रिटर्न वांछित परिणाम:

id | title |   date_created   | object_id | vote | sum 

11 | sdfg | 2012-06-04 23:30:17.805671-07 |  11 | 1 | 2 

1 | test | 2012-05-13 17:03:24.206092-07 |   1 | 1 | 2 

3 | asdf | 2012-05-13 19:23:15.059135-07 |   3 | 1 | 2 

2 | adsf | 2012-05-13 19:21:34.180905-07 |   2 | 1 | 2 

12 | 11  | 2012-06-04 23:30:54.759158-07 |  12 | 1 | 2 

9 | asfd | 2012-05-24 00:26:26.705843-07 |   9 | -1 | -1 

4 | asdf | 2012-05-14 19:59:52.450693-07 |   4 | -1 | -2 

समस्या है, मुझे यकीन है कि कैसे एक क्वेरीसमूह के रूप में इस पुनः प्राप्त करने के लिए नहीं कर रहा हूँ। फिलहाल मैं वस्तुओं को प्रदर्शित करने के निम्नलिखित का उपयोग कर रहा:

topic_list = Topic.objects.all() 

सब कुछ प्रदर्शित करता है के रूप में मैं यह करना चाहते हैं, सॉर्ट क्रम को छोड़कर। मैं पहले प्रदर्शित करने के लिए उच्चतम स्कोर चाहते हैं।

संसाधन मैं पहले से ही पर ध्यान दिया है: https://docs.djangoproject.com/en/dev/topics/db/managers/#adding-extra-manager-methods
How to query as GROUP BY in django?

और बहुत से अधिक है, लेकिन एक नया उपयोगकर्ता के रूप में, एंटी-स्पैम मुझे उन्हें जोड़ने से रोकता है।

बात की मैं कोशिश की है:

चेन:

listed_links = list(chain(topic, score)) 

दुर्भाग्य से, अगर मैं एक क्रमबद्ध मूल्य इस तोड़ दिया जोड़ने की कोशिश की।

का मेल वस्तु सूचियां:

topic = Topic.objects.all().values_list('user','id', 'title','slug', 'date_created', 'date_updated',) 

score = Vote.objects.values('object_id').annotate(total=Sum('vote')).order_by('-total') 

results = [] 

for topic in topic: 
results.append(topic) 

for score in score: 
results.append(topic) 

यह सभी वस्तुओं मैं एक सूची में चाहते थे में हुई है, लेकिन मैं समझ नहीं सकता score.object_id को topic.id कैसे लिंक करें।

मैंने कच्चे एसक्यूएल डालने का भी प्रयास किया है, लेकिन मुझे नहीं लगता कि मैं इसे सही तरीके से कर रहा हूं, और किसी तीसरे पक्ष द्वारा एसक्यूएल इंजेक्शन का कारण बन सकता है।

मुझे इस परिणाम को डीजेंगो-वोटिंग प्रोजेक्ट में साझा करना अच्छा लगेगा। जैसे मैंने कहा, सबकुछ काम करता है जैसा कि इसे करना चाहिए, सिवाय इसके कि मैं समझ नहीं सकता कि स्कोर desc द्वारा क्रमबद्ध कैसे करें।

============= वोटिंग ========================

from django.contrib.contenttypes import generic 

from django.contrib.contenttypes.models import ContentType 

from django.contrib.auth.models import User 

from django.db import models 

from voting.managers import VoteManager 

from voting.VotedObjectsManager import VotedObjectsManager 

    SCORES = (
    (+1, u'+1'), 
    (-1, u'-1'), 
) 

class Vote(models.Model): 

    """ 
    A vote on an object by a User. 
    """ 

    user   = models.ForeignKey(User) 

    content_type = models.ForeignKey(ContentType) 

    object_id = models.PositiveIntegerField() 

    object  = generic.GenericForeignKey('content_type', 'object_id') 

    vote   = models.SmallIntegerField(choices=SCORES) 

    objects  = VoteManager() 


    class Meta: 
     db_table = 'votes' 
     # One vote per user per object 
     unique_together = (('user', 'content_type', 'object_id'),) 

    def __unicode__(self): 
     return u'%s: %s on %s' % (self.user, self.vote, self.object) 

    def is_upvote(self): 
     return self.vote == 1 

    def is_downvote(self): 
     return self.vote == -1 

============= विषय मॉडल ========================

from django.db import models 

from datetime import datetime 

from tinymce import models as tinymce_models 

from django.forms import ModelForm 

from django.template.defaultfilters import slugify 

from tagging.fields import TagField 

from tagging.models import Tag 

from django.contrib.auth.models import User 

from django.utils.translation import ugettext_lazy as _ 

from django.contrib.contenttypes.models import ContentType 

from django.contrib.contenttypes import generic 

from django.core import urlresolvers 

    class Topic(models.Model): 

    title   = models.CharField(max_length=50) 

    slug   = models.SlugField(max_length=50, editable=False) 

    topic   = tinymce_models.HTMLField() 

    date_created = models.DateTimeField(editable=False) 

    date_updated = models.DateTimeField(editable=False) 

    tags   = TagField() 


    def set_tags(self, tags): 
     Tag.objects.update_tags(self, tags)  

    def __unicode__(self): 
     return self.tags 

    def __unicode__(self): 
     return self.id 

    def __unicode__(self): 
     return self.title 
+0

मॉडल हैं ...? –

+0

मैंने मॉडल जोड़े। त्वरित प्रतिक्रिया के लिए धन्यवाद। – user1462141

उत्तर

3

मैं यहां बताए अनुसार समाधान एक पैच का उपयोग कर यह पता लगाने में सक्षम था वोटिंग/managers.py फ़ाइल इस प्रकार है:

class VoteManager(models.Manager): 
def get_score(self, obj): 
    """ 
    Get a dictionary containing the total score for ``obj`` and 
    the number of votes it's received. 
    """ 
    ctype = ContentType.objects.get_for_model(obj) 
    result = self.filter(object_id=obj._get_pk_val(), 
         content_type=ctype).extra(
     select={ 
      'score': 'COALESCE(SUM(vote), 0)', 
      'num_votes': 'COALESCE(COUNT(vote), 0)', 
    }).values_list('score', 'num_votes')[0] 

    return { 
     'score': int(result[0]), 
     'num_votes': int(result[1]), 
    } 

तब मेरे topic.views.py में मैं जोड़ा निम्नलिखित:

from voting.managers import VoteManager 
def index(request): 
queryset = Topic.objects.select_score().order_by('-score') 
paginator = Paginator(queryset, 3) # Show 25 contacts per page 

page = request.GET.get('page') 
try: 
    topic_list = paginator.page(page) 
except PageNotAnInteger: 
    # If page is not an integer, deliver first page. 
    topic_list = paginator.page(1) 
except EmptyPage: 
    #If page is out of range (e.g. 9999), deliver last page of results. 
    topic_list = paginator.page(paginator.num_pages) 

c = Context({ 
'topic_list': topic_list, 
'request': request 
}) 
return render_to_response('idea/index.html', c, context_instance=RequestContext(request)) 

अन्त में, मेरी index.html में मैं जोड़ा निम्नलिखित लाइनों थोड़ा उपयोगकर्ताओं के लिए प्रदान की मूल उदाहरण से भी घूम:

{% load voting_tags %} 
{% votes_by_user user on topic_list as vote_dict %} 
{% scores_for_objects topic_list as score_dict %} 

<table id="voting_table" class="list"> 
<tbody> 
    {% for link in topic_list %} 
<td class="vote"> 

{% dict_entry_for_item link from vote_dict as vote %} 
{% dict_entry_for_item link from score_dict as score %} 

<div>  
<form class="linkvote" id="linkup{{ link.id }}"{% if vote and vote.is_upvote %} action="{% url link_vote object_id=link.id, direction="clear" %}"{% else %} action="{% url link_vote object_id=link.id, direction="up" %}"{% endif %} method="POST"> 
    <input type="image" id="linkuparrow{{ link.id }}" src="{{ STATIC_URL }}images/aup{% if vote and vote.is_upvote %}mod{% else %}grey{% endif %}.png"> 
    {% csrf_token %} 
    <input type="hidden" name="next" value="{{ request.get_full_path }}"/> 
    {% else %} 

    </form> 

     <div id="link_score">{{ score.score|default:0 }}</div> 

    <form class="linkvote" id="linkdown{{ link.id }}" {% if vote and vote.is_downvote %} action="{% url link_vote object_id=link.id, direction="clear" %}"{% else %} action="{% url link_vote object_id=link.id, direction="down" %}"{% endif %} method="POST"> 
    {% csrf_token %} 
    <input type="image" id="linkdownarrow{{ link.id }}" src="{{ STATIC_URL }}images/adown{% if vote and vote.is_downvote %}mod{% else %}grey{% endif %}.png"> 
    <input type="hidden" name="next" value="{{ request.get_full_path }}"/> 

</td> 
<td class="item"> 
    <a id="link_title" href="{{ link.id }}">{{ link.title|escape }}</a></h2> 
    <p class="details"> 
    <span class="score" id="linkscore{{ link.id }}" 
      title="after {{ score.num_votes|default:0 }} vote{{ score.num_votes|default:0|pluralize }}"> 
    </span> 
    posted {{ link.date_created|timesince }} ago by 
    <span class="user"><a href="../users/{{ link.user.id }}/">{{ link.owner|escape }}</a></span> 
{% get_comment_count for link as comment_count %} 
    <span id="comment_score" class="comment_details"> {{ comment_count }} comment{{ comment_count|pluralize }}</span> 
    </p> 
</td> 
</tr>{% endfor %} 
</tbody> 
    <td> 
    <div id="paginator" class="pagination"> 
    <span class="step-links"> 
     {% if topic_list.has_previous %} 
      <a href="?page={{ topic_list.previous_page_number }}">previous</a> 
    {% endif %} 
    {% if topic_list.has_next %} 
     <a href="?page={{ topic_list.next_page_number }}">next</a> 
    {% endif %} 
    </span> 
    </div> 
    </td> 
</table> 

संपादित

मैं लगभग भूल गया! यदि आप सूची को 2,1,0, -1, -2 जैसे ऑर्डर में सॉर्ट करना चाहते हैं, तो आप जो ऑब्जेक्ट बना रहे हैं उसे सबमिट करने पर वोट ऑब्जेक्ट वैल्यू सेट करना सुनिश्चित करें। नीचे दिया गया उदाहरण मेरे विषय से है .views.py

def submit_topic(request): 

if request.method == 'POST': 
    post_topic = PosttopicForm(request.POST) 
    owner = request.user 
    if post_topic.is_valid(): 
     topic = post_topic.save(commit=False) 
     topic.owner = request.user 
     topic.save() 
     vote = Vote(vote='0', user = request.user, content_type_id=10, object_id=topic.pk) 
     vote.save() 
     url = reverse('topic', args=[topic.pk, topic.slug]) 
     return HttpResponseRedirect(url) 
else: 
    post_topic = PosttopicForm() 

c = Context({ 
    'form': post_topic, 
    'user': request.user, 
    'request': request, 

})

return render_to_response('topic/submit.html', c, context_instance=RequestContext(request)) 

मैं वास्तव में इस किसी और में मदद करता है उम्मीद है। जल्द ही समाधान पोस्ट न करने के लिए खेद है। उम्मीद है कि कोई भी VOTManager से एसक्यूएल से छुटकारा पाने के द्वारा इसे बेहतर बना सकता है, लेकिन मुझे आगे बढ़ने की जरूरत है।

0

आप वोटों की राशि रखने के लिए विषय क्वेरीसेट को एनोटेट करने का प्रयास कर सकते हैं:

topic_list = Topic.objects.all().annotate(total=Sum('vote__vote')).order_by('-total') 

नोट: आपके मॉडल को देखे बिना, मुझे यकीन नहीं है कि Sum() फ़ंक्शन में क्या रखा जाए। यह मॉडल पर फ़ील्ड नाम के बाद बच्चे का मॉडल नाम होना चाहिए (जिसे मैं मानता हूं)।

def select_score(self): 
    """ Add vote scores for objects in resoultset """ 
    from django.contrib.contenttypes.models import ContentType 
    model_type = ContentType.objects.get_for_model(self.model) 
    table_name = self.model._meta.db_table 
    print type(model_type) 
    print model_type.id 
    return self.extra(select={'score': 'SELECT SUM(vote) FROM votes WHERE content_type_id=%i AND object_id=%s.id' % (int(model_type.id), table_name)}) 

और उन्हें कहा:

http://code.google.com/p/django-voting/issues/detail?id=10

अंतर यह है कि मैं निम्नलिखित लाइनों निकाला था:

+0

हाय नाथन! प्रतिक्रिया के लिए धन्यवाद। मेरी इच्छा है कि मैं इस विषय में जोड़े गए लिंक की संख्या से सीमित नहीं था। असुविधाजनक रूप से, मैंने पहले से ही कोशिश की है, और इसके परिणामस्वरूप: फ़ील्ड एरर: फ़ील्ड में कीवर्ड 'वोट' को हल नहीं कर सकता। विकल्प हैं: date_created, date_updated, id, owner, slug, टैग, शीर्षक – user1462141

+0

मुझे संदेह है कि यह GenericForeignKey के उपयोग से संबंधित है। मुझे विषय पर एक [जेनरिसरेलेशन] (https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/#reverse-generic-relations) नहीं दिख रहा है - क्या आपको इसे जोड़ने की ज़रूरत है ताकि आप इसे जोड़ सकें विषय से वोटों का उपयोग करें? – Nathan

+0

मुझे विश्वास है। डीजेंगो-वोटिंग ऐप वोटों के प्रबंधन के लिए एक सामान्य दृश्य का उपयोग करता है। https://code.google.com/p/django-voting/ – user1462141

संबंधित मुद्दे