Django:具有多个foreignKey的复杂Formset

时间:2012-12-17 07:54:31

标签: django foreign-key-relationship django-forms

我正在开展一个用户可以对书籍集合进行投票的项目。我的模型看起来像这样:

class Collection(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=31)

class Book(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=255)
    collection = models.ForeignKey(Collection)

vote_choices = ((-1,'Bad'),
                (0, 'Not good, Not bad'),
                (1,'Good'))

class Vote(models.Model):
    id = models.AutoField(primary_key=True)
    user = models.ForeignKey(User, related_name='votes')
    book = models.ForeignKey(Book)
    vote = models.IntegerField(choices=vote_choices)

我需要为用户显示一个视图,他们可以在这些视图中查看给定集合中的所有书籍,并立即为这些书籍投票,因为这比循环遍历每本书投票更加用户友好。所以我需要一个表单集,每个表单都是:一本书和它的投票。

最初我认为这是一个使用formset的好机会(我之前从未使用过它们,但我习惯使用表单,模型),但是我在如何创建这个formset时遇到了困难。 / p>

我想使用基于通用类的视图,因为从理论上讲,我可以轻松地轻松创建/更新所有投票,但我无法弄清楚如何执行此操作。

现在,我没有Collection模型和User(来自django.contrib.auth.model)模型之间的直接关系,但我不介意添加一个,如果这使事情变得更容易。我真的不需要一个,因为每个用户都通过投票链接到一本书,每本书都链接到一个集合。

我不确定是应该使用formset还是仅使用常规模型。

你会怎么做?提前感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

我建议不要在这种情况下使用django表单。有一些更方便的方法。

第一种方式。使用纯jQuery

扩展您的图书课程:

class Book(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=255)
    collection = models.ForeignKey(Collection, related_name='books')

    def get_vote(self, user):
        vote = Vote.objects.filter(book=self, user=user)
        if vote:
            return vote.vote
        else:
            return ''

您的观点(如果您愿意,可以在CBV上重写):

def list_collection(request, collection_id):
    collection = Collection.objects.get(pk=id)
    user = request.user
    books = []
    for item in collection.books.all():
        book = {
            'id': item.pk,
            'name': item.name,
            'vote': item.get_vote(user)
        }       
        books.append(book)
    return render_to_response('colleciton.html', {'books': books})

def set_vote(request):
    id = request.GET('id')
    vote = int(request.GET('vote'))
    user = request.user
    book = Book.objects.get(pk=id)
    vote = Vote()
    vote.user = user
    vote.vote = vote
    vote.book = book
    vote.save()
    return HttpResponse()

您的网址:

url(r'^list-collection/', 'list_collection', name='list_collection'),
url(r'^set-vote/', 'set_vote', name='set_vote'),

你的django模板:

{% extends 'base.html' %}
{% block content %}
    {% for book in collection.books.all %}
        <div class="book" data-id="{{ book.id }}">
            <div class="book-name">{{ book.name]}</div>
            <div class="book-vote" {% if not book.get_vote %}style="display:none"{% endif %}>book.get_vote</div>
            <div class="voting" {% if book.get_vote %}style="display:none"{% endif %}>
                <button class="vote-up"></button>
                <button class="vote-down"></button>
            </div>
        </div>
    {% endfor %}
{% endblock %}

javascript就像

$(document).ready(function(){
    $('.vote-up, .vote-down').on('click', function(e){
            var id, vote, t, book_el;
            e.preventDefault();
            t = $(e.currentTarget);
            book_el = t.parents().parents()
            id = book_el.attr('data-id');
            if t.hasClass('vote-up'){
                vote = 1;
            } else {
                vote = -1;
            }
            book_el.find('.book-vote').show();
            book_el.find('.book-vote').text(vote);
            book_el.find('voting').hide();
            $.get("/set-vote", {vote: vote, id: id});
        }); 
});

第二种方式。使用像Backbone.js

这样的javascript框架

它使整个过程变得更加容易。特别是如果您计划在应用中添加其他功能。 另一方面,Backbone需要一些时间来学习它。

Read the docslook at the tutorial app TodoMVCother tutorials。 也许你会发现它更适合你的任务。