From ab23f1604750ae6a9a94a54dc74c194e72f4ce74 Mon Sep 17 00:00:00 2001 From: Sanj Date: Thu, 19 Jul 2012 00:10:17 +0530 Subject: [PATCH] popup_form and autocomplete made single views in app.views --- itf/app/models.py | 31 +++++++++++-- itf/app/views.py | 45 +++++++++++++++++-- itf/insidepages/views.py | 12 ++--- itf/itfprofiles/forms.py | 62 +++++++++++++++++++------- itf/itfprofiles/models.py | 16 ++++--- itf/templates/formwidgets/select2.html | 2 + itf/templates/test/person_form.html | 38 ++++++++++++++++ itf/urls.py | 4 +- 8 files changed, 175 insertions(+), 35 deletions(-) create mode 100644 itf/templates/formwidgets/select2.html diff --git a/itf/app/models.py b/itf/app/models.py index 02cfa01..3558cdd 100755 --- a/itf/app/models.py +++ b/itf/app/models.py @@ -30,10 +30,11 @@ def get_real_ctype(module_name): return None -''' -Base models class that all other models that have front-end views inherit from. It handles passing of parameters to generate the list of items on the left, as well as methods (that can be over-ridden) to generate the context to be sent to the template that renders the object. -''' + class ItfModel(models.Model): + ''' + Base models class that all other models that have front-end views inherit from. It handles passing of parameters to generate the list of items on the left, as well as methods (that can be over-ridden) to generate the context to be sent to the template that renders the object. + ''' fts_fields = [] #Fields that should be text-searchable through fk_filters = [] #Foreign key fields that should be filterable by # related_models = [] @@ -66,6 +67,12 @@ class ItfModel(models.Model): 'title': self.get_title() } + #Data that's used by the autocomplete views + def autocomplete_dict(self): + d = self.list_dict() + d['text'] = self.get_text() + return d + #This should return all the context for the object that will get passed to the sub-template for this object. def info_dict(self): d = self.get_dict() @@ -79,6 +86,17 @@ class ItfModel(models.Model): return self.get(self.title_field) + #Returns "text" for this object - like a "description" or "about" field, or nothing - ideally would be over-ridden by subclasses. + def get_text(self): + try: + return self.description + except: + try: + return self.about + except: + pass + return '' + #Get the ModuleTab object associated with this object. def get_tab(self): modelextra = self.get_modelextra() @@ -102,6 +120,13 @@ class ItfModel(models.Model): ret[form_name] = get_form(form_name) return ret + @classmethod + def get_popup_form(cls): + all_forms = cls.get_forms() + for k in all_forms.keys(): + if k.startswith("Popup"): + return all_forms[k] + return all_forms[0] ''' Get the insidepages.models.ModelExtra object associated with this model diff --git a/itf/app/views.py b/itf/app/views.py index 45a16d9..e54b3f6 100755 --- a/itf/app/views.py +++ b/itf/app/views.py @@ -1,18 +1,57 @@ from django.template import RequestContext from django.conf import settings from django.shortcuts import render_to_response, get_object_or_404, get_list_or_404 - +from django.core.paginator import Paginator, InvalidPage, EmptyPage from ox.django.shortcuts import json_response, render_to_json_response, get_object_or_404_json -from api.views import html_snapshot - +#from api.views import html_snapshot +from django.contrib.contenttypes.models import ContentType +''' def index(request): context = RequestContext(request, {'settings':settings}) if request.GET.get('_escaped_fragment_', None): return html_snapshot(request) return render_to_response('index.html', context) +''' +def autocomplete(request, ctype_id): + q = request.GET.get('q', '') + if q == '': + q = 'a' + page = int(request.GET.get('page', '1')) + page_limit = int(request.GET.get('page_limit', '10')) + ctype = get_object_or_404_json(ContentType, pk=ctype_id) + model_class = ctype.model_class() + #model_class = ContentType.objects.get_for_id(ctype_id) + qset = model_class.get_qset() + all_results = model_class.fts(qset, q) + paginator = Paginator(qset, page_limit) + results = paginator.page(page) + items = [obj.autocomplete_dict() for obj in results.object_list] + ret = { + 'items': items, + 'has_next': results.has_next() + } + return render_to_json_response(ret) + + +def popup_form(request, ctype_id): + ctype = get_object_or_404(ContentType, pk=ctype_id) + model_class = ctype.model_class() + form_class = model_class.get_popup_form() + if request.POST: + form = form_class(request.POST, request.FILES) + if form.is_valid(): + instance = form.save() + text = instance.autocomplete_dict()['text'] + return HttpResponse("" % (instance.id, text,)) + else: + form = form_class() + context = RequestContext(request, { + 'form': form + }) + return render_to_response("test/popup.html", context) def site_json(request): diff --git a/itf/insidepages/views.py b/itf/insidepages/views.py index 42a75b5..d4d84a0 100755 --- a/itf/insidepages/views.py +++ b/itf/insidepages/views.py @@ -45,12 +45,14 @@ def edit_object(request, module_slug, tab_slug, object_id): return render_to_response("edit_form.html", context) -''' -Main function that handles incoming requests: - http:///m///?object_id=&search=&sort=&page=&count= - All options / parameters after are optional. -''' def render_object(request, module_slug): + ''' + Main function that handles incoming requests: + http:///m///?object_id=&search=&sort=&page=&count= + + All options / parameters after are optional. + + ''' #Get the module from module slug in URL, else return a 404 module = get_object_or_404(Module, slug=module_slug) diff --git a/itf/itfprofiles/forms.py b/itf/itfprofiles/forms.py index 8056024..38c0571 100644 --- a/itf/itfprofiles/forms.py +++ b/itf/itfprofiles/forms.py @@ -8,6 +8,8 @@ from django.contrib.contenttypes.generic import generic_inlineformset_factory from padmavideos.models import PadmaVideo, PadmaClip from crispy_forms.helper import FormHelper from crispy_forms.layout import Submit +from django.contrib.contenttypes.models import ContentType + class ItfForm(forms.ModelForm): @@ -17,23 +19,50 @@ class ItfForm(forms.ModelForm): super(ItfForm, self).__init__(*args, **kwargs) -class ConnectionsWidget(forms.SelectMultiple): - template_name = 'formwidgets/select2_multiple.html' +class PopupForm(ItfForm): + ''' + All popup forms inherit from this + ''' + pass + + +class PopupPersonForm(PopupForm): + + class Meta: + model = Person + + +class AutocompleteAddWidget(forms.Select): + template_name = 'formwidgets/select2.html' + + def __init__(self, *args, **kwargs): + ctype = kwargs.pop('ctype') + self.ctype = ctype + super(AutocompleteAddWidget, self).__init__(*args, **kwargs) - ''' - def get_context_data(self): - ctx = super(ConnectionsWidget, self).get_context_data() - - #ctx['data_json'] = [{'id': obj[0], 'text': obj[1]} for obj in self.choices] - return ctx - ''' - def get_context(self, name, value, attrs, *args, **kwargs): - ctx = super(ConnectionsWidget, self).get_context(name, value, attrs) - ctx['popup_url'] = '/m/person/popup' #FIXME: url scheme, also, a better way to pass this context to the widget template. - #selected_values = [{'id': obj[0], 'text': obj[1]} for obj in self.choices if obj[0] in value] - #ctx['data_json'] = json.dumps(selected_values) # json.dumps(choices) + ctx = super(AutocompleteAddWidget, self).get_context(name, value, attrs) + ctx['ctype'] = self.ctype return ctx + + +#class ConnectionsWidget(forms.SelectMultiple): +# template_name = 'formwidgets/select2_multiple.html' + +# ''' +# def get_context_data(self): +# ctx = super(ConnectionsWidget, self).get_context_data() +# +# #ctx['data_json'] = [{'id': obj[0], 'text': obj[1]} for obj in self.choices] +# return ctx +# ''' +# +# def get_context(self, name, value, attrs, *args, **kwargs): +# ctx = super(ConnectionsWidget, self).get_context(name, value, attrs) +# ctx['popup_url'] = '/m/person/popup' #FIXME: url scheme, also, a better way to pass this context to the widget template. +# #selected_values = [{'id': obj[0], 'text': obj[1]} for obj in self.choices if obj[0] in value] +# #ctx['data_json'] = json.dumps(selected_values) # json.dumps(choices) +# return ctx class ItfAllAuthRegForm(forms.Form): firstname=forms.CharField() @@ -42,7 +71,7 @@ class ItfAllAuthRegForm(forms.Form): def save(self, user): first_name = self.cleaned_data['firstname'] last_name = self.cleaned_data['lastname'] - p = Person(user=user, first_name=first_name, last_name=last_name) + p = Person(user=user, first_name=first_name, last_name=last_name, email=user.email) p.save() return self @@ -57,7 +86,8 @@ class ItfRegistrationForm(RegistrationForm): class ConnectionsForm(ItfForm): - person2 = forms.ModelMultipleChoiceField(Person.objects.all(), widget=ConnectionsWidget()) + ctype = ContentType.objects.get_for_model(Person) + person2 = forms.ModelChoiceField(Person.objects.all(), widget=AutocompleteAddWidget(ctype=ctype)) class Meta: model = PersonPerson diff --git a/itf/itfprofiles/models.py b/itf/itfprofiles/models.py index 21b07a4..a679dfa 100644 --- a/itf/itfprofiles/models.py +++ b/itf/itfprofiles/models.py @@ -13,30 +13,30 @@ GENDER_CHOICES = ( class Person(ItfModel): #ItfModel stuff: - form_names = ['PersonForm'] + form_names = ['PersonForm', 'PopupPersonForm'] fts_fields = ['first_name', 'last_name', 'email', 'about'] #Basic Info user = models.ForeignKey(User, blank=True, null=True, db_index=True, editable=False) first_name = models.CharField(max_length=255) last_name = models.CharField(max_length=255) email = models.EmailField(blank=True, null=True, unique=True, db_index=True) - email_validated = models.BooleanField(default=False, editable=False) +# email_validated = models.BooleanField(default=False, editable=False) tel_no = models.CharField(max_length=100, blank=True) about = models.TextField(blank=True, null=True) + dob = models.DateField(null=True, verbose_name="Date of Birth") + is_practitioner = models.BooleanField(default=False) + is_enthusiast = models.BooleanField(default=True) + is_freelancer = models.BooleanField(default=False) #Occupation info occupations = models.ManyToManyField("Occupation", through='PersonOccupation', blank=True, null=True) - is_practitioner = models.BooleanField(default=False) - is_enthusiast = models.BooleanField(default=True) #Personal info - dob = models.DateField(null=True, verbose_name="Date of Birth") gender = models.CharField(max_length=255, choices=GENDER_CHOICES, blank=True) image = models.ImageField(upload_to='images/', blank=True, null=True) locations = models.ManyToManyField("Location", blank=True, null=True) #Groups and Connections - is_freelancer = models.BooleanField(default=False) groups = models.ManyToManyField("TheatreGroup", blank=True, null=True, through='PersonGroup') connections = models.ManyToManyField('Person', blank=True, null=True, through='PersonPerson') productions = models.ManyToManyField("Production", blank=True, null=True, through='PersonProduction') @@ -55,7 +55,9 @@ class Person(ItfModel): def __unicode__(self): return "%s %s" % (self.first_name, self.last_name,) - + def get_title(self): + return self.__unicode__() + class Occupation(models.Model): name = models.CharField(max_length=255) diff --git a/itf/templates/formwidgets/select2.html b/itf/templates/formwidgets/select2.html new file mode 100644 index 0000000..b9e6386 --- /dev/null +++ b/itf/templates/formwidgets/select2.html @@ -0,0 +1,2 @@ + Add + diff --git a/itf/templates/test/person_form.html b/itf/templates/test/person_form.html index 89255a2..4bb2518 100644 --- a/itf/templates/test/person_form.html +++ b/itf/templates/test/person_form.html @@ -32,6 +32,7 @@ $(function(){ }); */ +/* sampleData = [ { 'id': 'foo', @@ -40,7 +41,43 @@ $(function(){ 'last_name': 'test' } ]; +*/ + $('.select2class').each(function() { + var ctype_id = $(this).attr("data-ctype"); + var url = '/autocomplete/' + ctype_id; + $(this).select2({ + ajax: { + 'url': url, + dataType: 'json', + quietMillis: 100, + data: function(term, page) { + return { + q: term, + page_limit: 10, + page: page + } + }, + results: function(data, page) { + //console.log(data); + var more = data.has_next; + //console.log(data); + return {results: data.items, more: more}; + } + }, + formatResult: function(item) { + return "
" + item.title + "
" + item.text + "
" + }, + formatSelection: function(item) { + //console.log(item); + //return "
" + item.first_name + " " + item.last_name + "
" + item.about + "
"; + //console.log("foo"); + return item.title; + //return "
" + item.first_name + " " + item.last_name + "
"; + } + }); + }); +/* $('.select2class').select2({ //placeholder: 'Select your connections', //multiple: true, @@ -87,6 +124,7 @@ $(function(){ } } }); +*/ // console.log(sampleData); // $('#id_connections').select2("val", sampleData); diff --git a/itf/urls.py b/itf/urls.py index 37fd1ef..6759944 100755 --- a/itf/urls.py +++ b/itf/urls.py @@ -43,7 +43,9 @@ urlpatterns = patterns('', #Test views: (r'test_profile', 'itfprofiles.views.person_form'), (r'edit_profile', 'itfprofiles.views.edit_profile'), - (r'^autocompletes/itfprofiles/$', 'itfprofiles.views.autocomplete'), + (r'^autocomplete/(?P\d+)', 'app.views.autocomplete'), + (r'^popup_form/(?P\d+)', 'app.views.popup_form'), +# (r'^autocompletes/itfprofiles/$', 'itfprofiles.views.autocomplete'), (r'^popup/person', 'itfprofiles.views.personpopup'), # (r'i/', include('itfcore.urls')), (r'^admin/doc/', include('django.contrib.admindocs.urls')),