Adding Tagging support.

This commit is contained in:
AppleGrew (applegrew) 2013-09-16 02:03:08 +05:30
parent 12ad5255d0
commit ab57470b02
14 changed files with 289 additions and 18 deletions

3
README
View file

@ -49,9 +49,10 @@ Special Thanks
Changelog Summary
=================
### v4.1.1
### v4.2.0
* Updated Select2 to version 3.4.2. **Please note**, that if you need any of the Select2 locale files, then you need to download them yourself from http://ivaynberg.github.com/select2/ and add to your project.
* Tagging support added. See [Field API reference](http://django-select2.readthedocs.org/en/latest/ref_fields.html) in documentation.
### v4.1.0

View file

@ -49,9 +49,10 @@ Special Thanks
Changelog Summary
=================
### v4.1.1
### v4.2.0
* Updated Select2 to version 3.4.2. **Please note**, that if you need any of the Select2 locale files, then you need to download them yourself from http://ivaynberg.github.com/select2/ and add to your project.
* Tagging support added. See [Field API reference](http://django-select2.readthedocs.org/en/latest/ref_fields.html) in documentation.
### v4.1.0

View file

@ -38,7 +38,8 @@ in their names.
**Available widgets:**
:py:class:`.Select2Widget`, :py:class:`.Select2MultipleWidget`, :py:class:`.HeavySelect2Widget`, :py:class:`.HeavySelect2MultipleWidget`,
:py:class:`.AutoHeavySelect2Widget`, :py:class:`.AutoHeavySelect2MultipleWidget`
:py:class:`.AutoHeavySelect2Widget`, :py:class:`.AutoHeavySelect2MultipleWidget`, :py:class:`.HeavySelect2TagWidget`,
:py:class:`.AutoHeavySelect2TagWidget`
`Read more`_
@ -57,7 +58,8 @@ your ease.
:py:class:`.HeavySelect2MultipleChoiceField`, :py:class:`.HeavyModelSelect2ChoiceField`,
:py:class:`.HeavyModelSelect2MultipleChoiceField`, :py:class:`.ModelSelect2Field`, :py:class:`.ModelSelect2MultipleField`,
:py:class:`.AutoSelect2Field`, :py:class:`.AutoSelect2MultipleField`, :py:class:`.AutoModelSelect2Field`,
:py:class:`.AutoModelSelect2MultipleField`
:py:class:`.AutoModelSelect2MultipleField`, :py:class:`.HeavySelect2TagField`, :py:class:`.AutoSelect2TagField`,
:py:class:`.HeavyModelSelect2TagField`, :py:class:`.AutoModelSelect2TagField`
Views
-----
@ -77,7 +79,7 @@ The view - `Select2View`, exposed here is meant to be used with 'Heavy' fields a
import logging
logger = logging.getLogger(__name__)
__version__ = "4.1.1"
__version__ = "4.2.0"
__RENDER_SELECT2_STATICS = False
__ENABLE_MULTI_PROCESS_SUPPORT = False
@ -89,6 +91,8 @@ __SECRET_SALT = ''
try:
from django.conf import settings
if logger.isEnabledFor(logging.INFO):
logger.info("Django found.")
if settings.configured:
__RENDER_SELECT2_STATICS = getattr(settings, 'AUTO_RENDER_SELECT2_STATICS', True)
__ENABLE_MULTI_PROCESS_SUPPORT = getattr(settings, 'ENABLE_SELECT2_MULTI_PROCESS_SUPPORT', False)
@ -103,12 +107,16 @@ try:
__ENABLE_MULTI_PROCESS_SUPPORT = False
from .widgets import Select2Widget, Select2MultipleWidget, HeavySelect2Widget, HeavySelect2MultipleWidget, \
AutoHeavySelect2Widget, AutoHeavySelect2MultipleWidget
AutoHeavySelect2Widget, AutoHeavySelect2MultipleWidget, HeavySelect2TagWidget, AutoHeavySelect2TagWidget
from .fields import Select2ChoiceField, Select2MultipleChoiceField, HeavySelect2ChoiceField, \
HeavySelect2MultipleChoiceField, HeavyModelSelect2ChoiceField, HeavyModelSelect2MultipleChoiceField, \
ModelSelect2Field, ModelSelect2MultipleField, AutoSelect2Field, AutoSelect2MultipleField, \
AutoModelSelect2Field, AutoModelSelect2MultipleField
AutoModelSelect2Field, AutoModelSelect2MultipleField, HeavySelect2TagField, AutoSelect2TagField, \
HeavyModelSelect2TagField, AutoModelSelect2TagField
from .views import Select2View, NO_ERR_RESP
if logger.isEnabledFor(logging.INFO):
logger.info("Django found and fields and widgest loaded.")
except ImportError:
if logger.isEnabledFor(logging.INFO):
logger.info("Django not found.")

View file

@ -82,11 +82,12 @@ from django.core.exceptions import ValidationError
from django.forms.models import ModelChoiceIterator
from django.db.models import Q
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import smart_unicode
from django.utils.encoding import smart_unicode, force_unicode
from .widgets import Select2Widget, Select2MultipleWidget,\
HeavySelect2Widget, HeavySelect2MultipleWidget, AutoHeavySelect2Widget, \
AutoHeavySelect2MultipleWidget, AutoHeavySelect2Mixin
AutoHeavySelect2MultipleWidget, AutoHeavySelect2Mixin, AutoHeavySelect2TagWidget, \
HeavySelect2TagWidget
from .views import NO_ERR_RESP
from .util import extract_some_key_val
@ -585,6 +586,38 @@ class HeavySelect2MultipleChoiceField(HeavySelect2FieldBaseMixin, HeavyMultipleC
"Heavy Select2 Multiple Choice field."
widget = HeavySelect2MultipleWidget
class HeavySelect2TagField(HeavySelect2MultipleChoiceField):
"""
Heavy Select2 field for tagging.
.. warning:: :py:exc:`NotImplementedError` would be thrown if :py:meth:`create_new_value` is not implemented.
"""
widget = HeavySelect2TagWidget
def validate(self, value):
if self.required and not value:
raise ValidationError(self.error_messages['required'])
# Check if each value in the value list is in self.choices or
# the big data (i.e. validate_value() returns True).
# If not then calls create_new_value() to create the new value.
for i in range(0, len(value)):
val = value[i]
if not self.valid_value(val):
value[i] = self.create_new_value(val)
def create_new_value(self, value):
"""
This is called when the input value is not valid. This
allows you to add the value into the data-store. If that
is not done then eventually the validation will fail.
:param value: Invalid value entered by the user.
:type value: As coerced by :py:meth:`HeavyChoiceField.coerce_value`.
:return: The a new value, which could be the id (pk) of the created value.
:rtype: Any
"""
raise NotImplementedError
### Heavy field specialized for Models ###
@ -605,6 +638,92 @@ class HeavyModelSelect2MultipleChoiceField(HeavySelect2FieldBaseMixin, ModelMult
kwargs.pop('choices', None)
super(HeavyModelSelect2MultipleChoiceField, self).__init__(*args, **kwargs)
class HeavyModelSelect2TagField(HeavySelect2FieldBaseMixin, ModelMultipleChoiceField):
"""
Heavy Select2 field for tagging, specialized for Models.
.. warning:: :py:exc:`NotImplementedError` would be thrown if :py:meth:`get_model_field_values` is not implemented.
"""
widget = HeavySelect2TagWidget
def __init__(self, *args, **kwargs):
kwargs.pop('choices', None)
super(HeavyModelSelect2TagField, self).__init__(*args, **kwargs)
def to_python(self, value):
if value in EMPTY_VALUES:
return None
try:
key = self.to_field_name or 'pk'
value = self.queryset.get(**{key: value})
except ValueError, e:
raise ValidationError(self.error_messages['invalid_choice'])
except self.queryset.model.DoesNotExist:
value = self.create_new_value(value)
return value
def clean(self, value):
if self.required and not value:
raise ValidationError(self.error_messages['required'])
elif not self.required and not value:
return []
if not isinstance(value, (list, tuple)):
raise ValidationError(self.error_messages['list'])
new_values = []
key = self.to_field_name or 'pk'
for pk in list(value):
try:
self.queryset.filter(**{key: pk})
except ValueError:
value.remove(pk)
new_values.append(pk)
for val in new_values:
value.append(self.create_new_value(force_unicode(val)))
# Usually new_values will have list of new tags, but if the tag is
# suppose of type int then that could be interpreted as valid pk
# value and ValueError above won't be triggered.
# Below we find such tags and create them, by check if the pk
# actually exists.
qs = self.queryset.filter(**{'%s__in' % key: value})
pks = set([force_unicode(getattr(o, key)) for o in qs])
for i in range(0, len(value)):
val = force_unicode(value[i])
if val not in pks:
value[i] = self.create_new_value(val)
# Since this overrides the inherited ModelChoiceField.clean
# we run custom validators here
self.run_validators(value)
return qs
def create_new_value(self, value):
"""
This is called when the input value is not valid. This
allows you to add the value into the data-store. If that
is not done then eventually the validation will fail.
:param value: Invalid value entered by the user.
:type value: As coerced by :py:meth:`HeavyChoiceField.coerce_value`.
:return: The a new value, which could be the id (pk) of the created value.
:rtype: Any
"""
obj = self.queryset.create(**self.get_model_field_values(value))
return getattr(obj, self.to_field_name or 'pk')
def get_model_field_values(self, value):
"""
This is called when the input value is not valid and the field
tries to create a new model instance.
:param value: Invalid value entered by the user.
:type value: unicode
:return: Dict with attribute name - attribute value pair.
:rtype: dict
"""
raise NotImplementedError
### Heavy general field that uses central AutoView ###
@ -633,6 +752,17 @@ class AutoSelect2MultipleField(AutoViewFieldMixin, HeavySelect2MultipleChoiceFie
widget = AutoHeavySelect2MultipleWidget
class AutoSelect2TagField(AutoViewFieldMixin, HeavySelect2TagField):
"""
Auto Heavy Select2 field for tagging.
This needs to be subclassed. The first instance of a class (sub-class) is used to serve all incoming
json query requests for that type (class).
.. warning:: :py:exc:`NotImplementedError` would be thrown if :py:meth:`get_results` is not implemented.
"""
widget = AutoHeavySelect2TagWidget
### Heavy field, specialized for Model, that uses central AutoView ###
@ -663,3 +793,30 @@ class AutoModelSelect2MultipleField(ModelResultJsonMixin, AutoViewFieldMixin, He
widget = AutoHeavySelect2MultipleWidget
class AutoModelSelect2TagField(ModelResultJsonMixin, AutoViewFieldMixin, HeavyModelSelect2TagField):
"""
Auto Heavy Select2 field for tagging, specialized for Models.
This needs to be subclassed. The first instance of a class (sub-class) is used to serve all incoming
json query requests for that type (class).
.. warning:: :py:exc:`NotImplementedError` would be thrown if :py:meth:`get_model_field_values` is not implemented.
Example::
class Tag(models.Model):
tag = models.CharField(max_length=10, unique=True)
def __unicode__(self):
return unicode(self.tag)
class TagField(AutoModelSelect2TagField):
queryset = Tag.objects
search_fields = ['tag__icontains', ]
def get_model_field_values(self, value):
return {'tag': value}
"""
# Makes sure that user defined queryset class variable is replaced by
# queryset property (as it is needed by super classes).
__metaclass__ = UnhideableQuerysetType
widget = AutoHeavySelect2TagWidget

View file

@ -150,6 +150,16 @@ if (!window['django_select2']) {
callback(data); // Change for 2.3.x
django_select2.updateText(e);
},
createSearchChoice: function(term, data) {
if (!data || $(data).filter(function () {
return this.text.localeCompare(term) === 0;
}).length === 0) {
return {
id: term,
text: term
};
}
},
onMultipleHiddenChange: function () {
var $e = $(this), valContainer = $e.data('valContainer'), name = $e.data('name'), vals = $e.val();
valContainer.empty();

View file

@ -1 +1 @@
if(!window.django_select2){var django_select2={MULTISEPARATOR:String.fromCharCode(0),get_url_params:function(c,e,b){var d=$(this).data("field_id"),a={term:c,page:e,context:b};if(d){a.field_id=d}return a},process_results:function(d,c,b){var a;if(d.err&&d.err.toLowerCase()==="nil"){a={results:d.results};if(b){a.context=b}if(d.more===true||d.more===false){a.more=d.more}}else{a={results:[]}}if(a.results){$(this).data("results",a.results)}else{$(this).removeData("results")}return a},onValChange:function(){django_select2.updateText($(this))},prepareValText:function(d,a,c){var b=[];$(d).each(function(e){b.push({id:this,text:a[e]})});if(c){return b}else{if(b.length>0){return b[0]}else{return null}}},updateText:function(b){var f=b.select2("val"),d=b.select2("data"),a=b.txt(),c=!!b.attr("multiple"),e;if(f||f===0){if(c){if(f.length!==a.length){a=[];$(f).each(function(g){var h,j=this,k;for(h in d){k=d[h].id;if(k instanceof String){k=k.valueOf()}if(k==j){a.push(d[h].text)}}})}}else{a=d.text}b.txt(a)}else{b.txt("")}},getValText:function(b){var g=b.select2("val"),c=b.data("results"),a=b.txt(),e=!!b.attr("multiple"),d,h=b.attr("id");if(g||g===0){if(!e){g=[g];if(a||a===0){a=[a]}}if(a===0||(a&&g.length===a.length)){return[g,a]}d=b.data("userGetValText");if(d){a=d(b,g,e);if(a||a===0){return[g,a]}}if(c){a=[];$(g).each(function(f){var j,k=this;for(j in c){if(c[j].id==k){g[f]=c[j].id;a.push(c[j].text)}}});if(a||a===0){return[g,a]}}}return null},onInit:function(b,f){b=$(b);var d=b.attr("id"),a=null,c=b.select2("val");if(!c&&c!==0){c=b.data("initVal")}if(c||c===0){a=django_select2.getValText(b);if(a&&a[0]){a=django_select2.prepareValText(a[0],a[1],!!b.attr("multiple"))}}if(!a){b.val(null)}f(a);django_select2.updateText(b)},onMultipleHiddenChange:function(){var b=$(this),d=b.data("valContainer"),a=b.data("name"),c=b.val();d.empty();if(c){c=c.split(django_select2.MULTISEPARATOR);$(c).each(function(){var e=$('<input type="hidden">').appendTo(d);e.attr("name",a);e.val(this)})}},initMultipleHidden:function(a){var b;a.data("name",a.attr("name"));a.attr("name","");b=$("<div>").insertAfter(a).css({display:"none"});a.data("valContainer",b);a.change(django_select2.onMultipleHiddenChange);if(a.val()){a.change()}},convertArrToStr:function(a){return a.join(django_select2.MULTISEPARATOR)},runInContextHelper:function(a,b){return function(){var c=Array.prototype.slice.call(arguments,0);return a.apply($("#"+b).get(0),c)}},logErr:function(){if(console&&console.error){args=Array.prototype.slice.call(arguments);console.error.apply(console,args)}}};(function(b){if(b){for(var a in django_select2){var c=django_select2[a];if(typeof(c)=="function"){django_select2[a]=(function(d,e){return function(){console.log("Function "+d+" called for object: ",this);return e.apply(this,arguments)}}(a,c))}}}}(false));(function(a){a.fn.txt=function(b){if(typeof(b)!=="undefined"){if(b){if(b instanceof Array){if(this.attr("multiple")){b=django_select2.convertArrToStr(b)}else{b=b[0]}}this.attr("txt",b)}else{this.removeAttr("txt")}return this}else{b=this.attr("txt");if(this.attr("multiple")){if(b){b=b.split(django_select2.MULTISEPARATOR)}else{b=[]}}return b}}})(jQuery)};
if(!window.django_select2){var django_select2={MULTISEPARATOR:String.fromCharCode(0),get_url_params:function(c,e,b){var d=$(this).data("field_id"),a={term:c,page:e,context:b};if(d){a.field_id=d}return a},process_results:function(d,c,b){var a;if(d.err&&d.err.toLowerCase()==="nil"){a={results:d.results};if(b){a.context=b}if(d.more===true||d.more===false){a.more=d.more}}else{a={results:[]}}if(a.results){$(this).data("results",a.results)}else{$(this).removeData("results")}return a},onValChange:function(){django_select2.updateText($(this))},prepareValText:function(d,a,c){var b=[];$(d).each(function(e){b.push({id:this,text:a[e]})});if(c){return b}else{if(b.length>0){return b[0]}else{return null}}},updateText:function(b){var f=b.select2("val"),d=b.select2("data"),a=b.txt(),c=!!b.attr("multiple"),e;if(f||f===0){if(c){if(f.length!==a.length){a=[];$(f).each(function(g){var h,j=this,k;for(h in d){k=d[h].id;if(k instanceof String){k=k.valueOf()}if(k==j){a.push(d[h].text)}}})}}else{a=d.text}b.txt(a)}else{b.txt("")}},getValText:function(b){var g=b.select2("val"),c=b.data("results"),a=b.txt(),e=!!b.attr("multiple"),d,h=b.attr("id");if(g||g===0){if(!e){g=[g];if(a||a===0){a=[a]}}if(a===0||(a&&g.length===a.length)){return[g,a]}d=b.data("userGetValText");if(d){a=d(b,g,e);if(a||a===0){return[g,a]}}if(c){a=[];$(g).each(function(f){var j,k=this;for(j in c){if(c[j].id==k){g[f]=c[j].id;a.push(c[j].text)}}});if(a||a===0){return[g,a]}}}return null},onInit:function(b,f){b=$(b);var d=b.attr("id"),a=null,c=b.select2("val");if(!c&&c!==0){c=b.data("initVal")}if(c||c===0){a=django_select2.getValText(b);if(a&&a[0]){a=django_select2.prepareValText(a[0],a[1],!!b.attr("multiple"))}}if(!a){b.val(null)}f(a);django_select2.updateText(b)},createSearchChoice:function(a,b){if(!b||$(b).filter(function(){return this.text.localeCompare(a)===0}).length===0){return{id:a,text:a}}},onMultipleHiddenChange:function(){var b=$(this),d=b.data("valContainer"),a=b.data("name"),c=b.val();d.empty();if(c){c=c.split(django_select2.MULTISEPARATOR);$(c).each(function(){var e=$('<input type="hidden">').appendTo(d);e.attr("name",a);e.val(this)})}},initMultipleHidden:function(a){var b;a.data("name",a.attr("name"));a.attr("name","");b=$("<div>").insertAfter(a).css({display:"none"});a.data("valContainer",b);a.change(django_select2.onMultipleHiddenChange);if(a.val()){a.change()}},convertArrToStr:function(a){return a.join(django_select2.MULTISEPARATOR)},runInContextHelper:function(a,b){return function(){var c=Array.prototype.slice.call(arguments,0);return a.apply($("#"+b).get(0),c)}},logErr:function(){if(console&&console.error){args=Array.prototype.slice.call(arguments);console.error.apply(console,args)}}};(function(b){if(b){for(var a in django_select2){var c=django_select2[a];if(typeof(c)=="function"){django_select2[a]=(function(d,e){return function(){console.log("Function "+d+" called for object: ",this);return e.apply(this,arguments)}}(a,c))}}}}(false));(function(a){a.fn.txt=function(b){if(typeof(b)!=="undefined"){if(b){if(b instanceof Array){if(this.attr("multiple")){b=django_select2.convertArrToStr(b)}else{b=b[0]}}this.attr("txt",b)}else{this.removeAttr("txt")}return this}else{b=this.attr("txt");if(this.attr("multiple")){if(b){b=b.split(django_select2.MULTISEPARATOR)}else{b=[]}}return b}}})(jQuery)};

View file

@ -504,7 +504,7 @@ class HeavySelect2MultipleWidget(HeavySelect2Mixin, MultipleSelect2HiddenInput):
Following Select2 options from :py:attr:`.Select2Mixin.options` are added or set:-
* multiple: ``False``
* multiple: ``True``
* separator: ``JSVar('django_select2.MULTISEPARATOR')``
"""
@ -539,6 +539,34 @@ class HeavySelect2MultipleWidget(HeavySelect2Mixin, MultipleSelect2HiddenInput):
if texts:
return u"$('#%s').txt(%s);" % (id_, texts)
class HeavySelect2TagWidget(HeavySelect2MultipleWidget):
"""
Heavy widget with tagging support. Based on :py:class:`HeavySelect2MultipleWidget`,
unlike other widgets this allows users to create new options (tags).
Following Select2 options from :py:attr:`.Select2Mixin.options` are removed:-
* allowClear
* minimumResultsForSearch
* closeOnSelect
Following Select2 options from :py:attr:`.Select2Mixin.options` are added or set:-
* multiple: ``True``
* separator: ``JSVar('django_select2.MULTISEPARATOR')``
* tags: ``True``
* tokenSeparators: ``,`` and `` ``
* createSearchChoice: ``JSFunctionInContext('django_select2.createSearchChoice')``
* minimumInputLength: ``1``
"""
def init_options(self):
super(HeavySelect2TagWidget, self).init_options()
self.options.pop('closeOnSelect', None)
self.options['minimumInputLength'] = 1
self.options['tags'] = True
self.options['tokenSeparators'] = [",", " "]
self.options['createSearchChoice'] = JSFunctionInContext('django_select2.createSearchChoice')
### Auto Heavy widgets ###
@ -571,3 +599,7 @@ class AutoHeavySelect2Widget(AutoHeavySelect2Mixin, HeavySelect2Widget):
class AutoHeavySelect2MultipleWidget(AutoHeavySelect2Mixin, HeavySelect2MultipleWidget):
"Auto version of :py:class:`.HeavySelect2MultipleWidget`"
pass
class AutoHeavySelect2TagWidget(AutoHeavySelect2Mixin, HeavySelect2TagWidget):
"Auto version of :py:class:`.HeavySelect2TagWidget`"
pass

Binary file not shown.

View file

@ -10,5 +10,6 @@
<li><a href="{% url 'test_multi_values_model_field' %}">Test multi selection model fields</a></li>
<li><a href="{% url 'test_mixed_form' %}">Test mixed form. All fields' search must return their own results, not other fields'.</a></li>
<li><a href="{% url 'test_init_values' %}">Test that initial values are honored in unbound form</a></li>
<li><a href="{% url 'test_list_questions' %}">Test tagging support</a></li>
</ul>
</body>

View file

@ -5,6 +5,10 @@
</head>
<body>
<h2>{{title}}</h2>
{% if create_new_href != '' %}
<a href="{% url create_new_href %}">Create New</a>
<br/>
{% endif %}
<ul>
{% for e in object_list %}
<li><a href="{% url href e.id %}">{{ e }}</a></li>

View file

@ -2,7 +2,7 @@ from django import forms
from django_select2 import *
from .models import Employee, Dept, ClassRoom, Lab, Word, School
from .models import Employee, Dept, ClassRoom, Lab, Word, School, Tag, Question
from django.core.exceptions import ValidationError
@ -27,6 +27,12 @@ class WordChoices(AutoModelSelect2Field):
queryset = Word.objects
search_fields = ['word__icontains', ]
class TagField(AutoModelSelect2TagField):
queryset = Tag.objects
search_fields = ['tag__icontains', ]
def get_model_field_values(self, value):
return {'tag': value}
class SelfChoices(AutoSelect2Field):
def get_val_txt(self, value):
if not hasattr(self, 'res_map'):
@ -147,3 +153,11 @@ class InitialValueForm(forms.Form):
heavySelect2ChoiceWithQuotes = AutoSelect2Field(initial=2,
choices=((1, "'Single-Quote'"), (2, "\"Double-Quotes\""), (3, "\"Mixed-Quotes'"), ))
class QuestionForm(forms.ModelForm):
question = forms.CharField()
description = forms.CharField(widget=forms.Textarea)
tags = TagField()
class Meta:
model = Question

View file

@ -37,5 +37,18 @@ class Word(models.Model):
class School(models.Model):
classes = models.ManyToManyField(ClassRoom)
class Tag(models.Model):
tag = models.CharField(max_length=10, unique=True)
def __unicode__(self):
return unicode(self.tag)
class Question(models.Model):
question = models.CharField(max_length=200)
description = models.CharField(max_length=800)
tags = models.ManyToManyField(Tag)
def __unicode__(self):
return unicode(self.question)

View file

@ -10,4 +10,8 @@ urlpatterns = patterns('testapp.testmain.views',
url(r'mixed/form/$', 'test_mixed_form', name='test_mixed_form'),
url(r'initial/form/$', 'test_init_values', name='test_init_values'),
url(r'question/$', 'test_list_questions', name='test_list_questions'),
url(r'question/form/([0-9]+)/$', 'test_tagging', name='test_tagging'),
url(r'question/form/$', 'test_tagging_new', name='test_tagging_new'),
)

View file

@ -2,15 +2,16 @@ from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
from django.shortcuts import render, get_object_or_404
from .forms import EmployeeForm, DeptForm, MixedForm, InitialValueForm
from .models import Employee, Dept
from .forms import EmployeeForm, DeptForm, MixedForm, InitialValueForm, QuestionForm
from .models import Employee, Dept, Question
def test_single_value_model_field(request):
return render(request, 'list.html', {
'title': 'Employees',
'href': 'test_single_value_model_field1',
'object_list': Employee.objects.all()
})
'object_list': Employee.objects.all(),
'create_new_href': ''
})
def test_single_value_model_field1(request, id):
emp = get_object_or_404(Employee, pk=id)
@ -28,7 +29,8 @@ def test_multi_values_model_field(request):
return render(request, 'list.html', {
'title': 'Departments',
'href': 'test_multi_values_model_field1',
'object_list': Dept.objects.all()
'object_list': Dept.objects.all(),
'create_new_href': ''
})
def test_multi_values_model_field1(request, id):
@ -53,4 +55,28 @@ def test_mixed_form(request):
def test_init_values(request):
return render(request, 'form.html', {'form': InitialValueForm()})
def test_list_questions(request):
return render(request, 'list.html', {
'title': 'Questions',
'href': 'test_tagging',
'object_list': Question.objects.all(),
'create_new_href': 'test_tagging_new'
})
def test_tagging_new(request):
return test_tagging(request, None)
def test_tagging(request, id):
if id is None:
question = Question()
else:
question = get_object_or_404(Question, pk=id)
if request.POST:
form = QuestionForm(data=request.POST, instance=question)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('home'))
else:
form = QuestionForm(instance=question)
return render(request, 'form.html', {'form': form})