Добавьте пользовательскую форму для пользователя в приложение Django (использует selectize и taggit)

Я новичок в django и пытаюсь понять, как создать форму с помощью taggit- выберите виджет (или django-taggit). Все, что я нашел в Интернете, относится к использованию страницы администратора, но я хочу, чтобы теги были видны пользователю и редактировались — так же, как теги, которые я создаю под этим постом. До сих пор я определил, что мне нужно создать форму с помощью виджета:

# models.py
from taggit_selectize.managers import TaggableManager
    tags = TaggableManager()

# forms.py
from taggit_selectize.widgets import TagSelectize
from .models import MyModel

class TagForm(forms.ModelForm):
    class Meta:
        model = MyModel
        fields = ('tags',)
        widgets = {'tags': TagSelectize(),}

но я не могу понять, как включить эту форму в свой шаблон, чтобы она отображалась рядом с моими MyModel объектами. В идеале я ожидал, что он будет вести себя как django-fluent-comments, где я могу просто позвонить {% render_comment_form for obj %} и положить этому конец.


Обновлять

Я отредактировал views (см. ниже) и теперь могу получить доступ к форме в шаблоне, но не могу отправить свои теги (в идеале это также не вызовет перенаправления).

# views.py
from .forms import TagForm
def show_tags(request):
    return render(request, 'tags.html', {'tagform' : TagForm})

# tags.html        
<div>
{{ tagform.media }}
{{ tagform.as_p }}
</div>

person Soul Donut    schedule 11.02.2016    source источник


Ответы (1)


Итак, я наконец понял это. Он включает в себя обертывание формы тега <form> тегами и перехват запроса POST. Для справки, это часть проекта, в котором используется Haystack для возврата списка результатов, которые я затем хочу пометить. Мой views.py является подклассом SearchView, а не определяет функцию, как я делаю здесь (show_tags()), и вместо одного объекта на странице у меня есть несколько.

Для объекта obj на странице у вас есть следующее

# views.py
from .forms import TagForm
from .models import MyModel
from django.views.decorators.http import require_POST
from django.views.decorators.csrf import csrf_exempt

def show_tags(request):

    # Perhaps the request specifies the object, but
    # for simplicity's sake we just pick a specific model instance
    object = MyModel.objects.filter(pk = 123) 
    return render(request, 'tags.html', {'tagform' : TagForm,
                                         'obj' : MyModel})

@require_POST
@csrf_exempt
def create_tag(request):
    # See javascript below for creation of POST request
    data = request.POST
    tag_text_raw = data.get('tag_data')

    # clean_tag() not shown, but it splits the serialized
    # tag_text_raw and returns a list of strings
    tag_text_clean = clean_tag(tag_text_raw)

    obj_pk = data.get('obj_pk')

    #save tags to document
    doc = DocInfo.objects.get(pk = obj_pk)
    doc.tags.add(*tag_text_clean)

    # not strictly necessary; mainly for logging
    response_data = {'tag_text': tag_text_clean,
                 'obj_pk': obj_pk
                 }

    return JsonResponse(response_data)

Таким образом, show_tags отправляет информацию в шаблон с помощью render, после чего шаблон получает доступ к этим объектам. Это то, что изначально не имело для меня смысла.

# tags.html (extends base.html)
{% block scripts %}{{ block.super }}
    <script type="text/javascript" src="{{ STATIC_URL }}js/ajaxtag.js"></script>
  {{ tagform.media }}
{% endblock %}    

{{ obj.text }}
<form method="post" action="create_tag/" id="tag-form-{{ obj.pk }}" name="tag-form-obj" data-object-id={{ obj.pk }}>
    {{ tagform.as_p }}
    <input type="submit" name ="tag-form-input" value="Add Tags" />
</form>

Мы можем поймать запрос POST с помощью javascript:

    #ajaxtag.js
    (function($)
    {
    // A stripped-down version of ajaxcomments.js from fluent_comments
    // See that file for further expansions
    $.fn.ready(function () {
        var tagform = $('form[name="tag-form-obj"]');

        if (tagform.length > 0) {
            // Detect last active input.
            // Submit if return is hit
            tagform.find(':input').focus(setActiveInput).mousedown(setActiveInput);
            tagform.submit(onTagFormSubmit);
        }
    });

    function onTagFormSubmit(event)
    {   
        event.preventDefault();  // prevents redirect
        var form = event.target;

        create_tag(form);
        return false;
    }

    function create_tag(form) 
    {
        console.log("create_tag is working!") // sanity check
        var $form = $(form);
        var tag_text = $form.serialize();
        var url = $form.attr('action');
        var obj_id = $form.attr('data-object-id')

        $.ajax({
            url : url,
            type: "POST",
            data: { tag_data: tag_text, obj_pk: obj_id},

            success: function (data) {
                data;
                console.log(data);
                console.log('success');
            },

            error: function (xhr, errmsg, err) {
                // Return error to console
                console.log(xhr.status + ": " + xhr.responseText)
            }
        });

    }

    function setActiveInput() {
        active_input = this.name;
    }

    })(window.jQuery);

Наконец, urls.py отправляет запрос обратно create_tag().

# urls.py
from .views import create_tag
...
url(r'^create_tag', create_tag, name = 'tag-form')
...
person Soul Donut    schedule 17.02.2016