-
-
Save luanfonceca/3894261 to your computer and use it in GitHub Desktop.
Django Tests with dynamic fields in hstore
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
*.pyc | |
.project | |
.pydevproject |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<form action="/hstoredyn/add" method="post">{% csrf_token %} | |
{{ form.as_p }} | |
<input type="submit" value="Submit" /> | |
</form> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' | |
Created on 13/10/2012 | |
@author: iuri | |
''' | |
from hstoredyn.models import Something | |
from django.contrib import admin | |
admin.site.register(Something) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{% if somethings_list %} | |
<ul> | |
{% for something in somethings_list %} | |
<li><a href="/hstoredyn/{{ something.id }}/">{{ something.name }}</a></li> | |
{% endfor %} | |
</ul> | |
{% else %} | |
<p>No data is available.</p> | |
{% endif %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import os | |
import sys | |
if __name__ == "__main__": | |
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "hstoredyn.settings") | |
from django.core.management import execute_from_command_line | |
execute_from_command_line(sys.argv) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' | |
Created on 13/10/2012 | |
@author: iuri | |
''' | |
from django.db import models | |
from django import forms | |
from django_orm.postgresql import hstore | |
from django.utils.datastructures import SortedDict | |
import copy | |
from django.forms.models import fields_for_model | |
class DynamicFields(models.Model): | |
refer = models.CharField(max_length=120, blank=False) | |
name = models.CharField(max_length=120, blank=False) | |
type = models.CharField(max_length=120, blank=False) | |
max_length = models.IntegerField(null=True, blank=True) | |
null = models.BooleanField(default=False) | |
blank = models.BooleanField(default=False) | |
choices = hstore.DictionaryField(null=True) | |
objects = hstore.HStoreManager() | |
###################################### | |
class MyModelMeta(models.Model.__metaclass__): | |
def __new__(cls, name, bases, attrs): | |
super_new = super(MyModelMeta, cls).__new__ | |
# create it | |
new_class = super_new(cls, name, bases, attrs) | |
# pos create | |
# override getattr/setattr/delattr | |
old_getattribute = new_class.__getattribute__ | |
def __getattribute__(self, key): | |
try: | |
return old_getattribute(self, key) | |
except AttributeError: | |
if hasattr(self, '_dfields') and key in self._dfields: | |
return self._dfields[key] | |
raise | |
new_class.__getattribute__ = __getattribute__ | |
old_setattr = new_class.__setattr__ | |
def __setattr__(self, key, value): | |
#print "called __setattr__(%r, %r)" % (key, value) | |
if hasattr(self, '_dfields') and not key in dir(new_class): | |
# XXX: search for key on table, django will call this method on many times on | |
# __init__ | |
if DynamicFields.objects.filter(refer=new_class.__name__, name=key): | |
self._dfields[key] = str(value) | |
return | |
old_setattr(self, key, value) | |
new_class.__setattr__ = __setattr__ | |
old_delattr = new_class.__delattr__ | |
def __delattr__(self, key): | |
if hasattr(self, '_dfields') and not key in dir(new_class): | |
if key in self._dfields: | |
del self._dfields[key] | |
return | |
return old_delattr(self, key) | |
new_class.__delattr__ = __delattr__ | |
# override _meta.fields (property) | |
_old_meta = new_class._meta | |
class _meta(object): | |
@property | |
def dynamic_fields(self): | |
fields = [] | |
for metafield in DynamicFields.objects.filter(refer=new_class.__name__): | |
type_ = metafield.type | |
try: | |
#FIXME: eval is the evil, use module package | |
field_klass = eval('models.%s' % type_) | |
field = field_klass(name=metafield.name, | |
max_length=metafield.max_length, | |
choices=metafield.choices.get('choices'), | |
blank=metafield.blank, | |
null=metafield.null) | |
field.attname = metafield.name | |
fields.append(field) | |
except: | |
raise \ | |
TypeError(('Cannot create field for %r, maybe type %r ' + \ | |
'is not a django type') % (metafield, type_)) | |
return fields | |
@property | |
def fields(self): | |
#add dynamic_fields from table | |
return _old_meta.fields + self.dynamic_fields | |
def __getattr__(self, key): | |
return getattr(_old_meta, key) | |
def __setattr__(self, key, value): | |
return setattr(_old_meta, key, value) | |
new_class._meta = _meta() | |
# return it | |
return new_class | |
class MyModel(models.Model): | |
__metaclass__ = MyModelMeta | |
objects = hstore.HStoreManager() | |
_dfields = hstore.DictionaryField(db_index=True) | |
class Meta: | |
abstract = True | |
def __init__(self, *args, **kwargs): | |
super(MyModel, self).__init__(*args, **kwargs) | |
class MyModelFormMeta(forms.ModelForm.__metaclass__): | |
def __new__(cls, name, bases, attrs): | |
super_new = super(MyModelFormMeta, cls).__new__ | |
# create it | |
new_class = super_new(cls, name, bases, attrs) | |
# pos create, remove _dfields | |
if '_dfields' in new_class.base_fields: | |
new_class.base_fields.pop('_dfields') | |
# return it | |
return new_class | |
class MyModelForm(forms.ModelForm): | |
__metaclass__ = MyModelFormMeta | |
def __init__(self, *args, **kwargs): | |
super(MyModelForm, self).__init__(*args, **kwargs) | |
# Always override for fields (dynamic fields maybe deleted/included) | |
opts = self._meta | |
if opts.model and issubclass(opts.model, MyModel): | |
# If a model is defined, extract dynamic form fields from it. | |
if not opts.exclude: | |
opts.exclude = [] | |
# hide dfields | |
opts.exclude.append('_dfields') | |
self.fields = fields_for_model(opts.model, opts.fields, | |
opts.exclude, opts.widgets) | |
####################################################### | |
class Something(MyModel): | |
name = models.CharField(max_length=32) | |
def __unicode__(self): | |
return self.name | |
class SomethingForm(MyModelForm): | |
class Meta: | |
model = Something | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Django settings for hstoredyn project. | |
DEBUG = True | |
TEMPLATE_DEBUG = DEBUG | |
ADMINS = ( | |
# ('Your Name', 'your_email@example.com'), | |
) | |
MANAGERS = ADMINS | |
DATABASES = { | |
'default': { | |
'ENGINE': 'django.db.backends.postgresql_psycopg2', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. | |
'NAME': 'hstore_test', # Or path to database file if using sqlite3. | |
'USER': 'iuri', # Not used with sqlite3. | |
'PASSWORD': '', # Not used with sqlite3. | |
'HOST': '', # Set to empty string for localhost. Not used with sqlite3. | |
'PORT': '', # Set to empty string for default. Not used with sqlite3. | |
} | |
} | |
# Local time zone for this installation. Choices can be found here: | |
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name | |
# although not all choices may be available on all operating systems. | |
# In a Windows environment this must be set to your system time zone. | |
TIME_ZONE = 'America/Fortaleza' | |
# Language code for this installation. All choices can be found here: | |
# http://www.i18nguy.com/unicode/language-identifiers.html | |
LANGUAGE_CODE = 'pt-br' | |
SITE_ID = 1 | |
# If you set this to False, Django will make some optimizations so as not | |
# to load the internationalization machinery. | |
USE_I18N = True | |
# If you set this to False, Django will not format dates, numbers and | |
# calendars according to the current locale. | |
USE_L10N = True | |
# If you set this to False, Django will not use timezone-aware datetimes. | |
USE_TZ = True | |
# Absolute filesystem path to the directory that will hold user-uploaded files. | |
# Example: "/home/media/media.lawrence.com/media/" | |
MEDIA_ROOT = '' | |
# URL that handles the media served from MEDIA_ROOT. Make sure to use a | |
# trailing slash. | |
# Examples: "http://media.lawrence.com/media/", "http://example.com/media/" | |
MEDIA_URL = '' | |
# Absolute path to the directory static files should be collected to. | |
# Don't put anything in this directory yourself; store your static files | |
# in apps' "static/" subdirectories and in STATICFILES_DIRS. | |
# Example: "/home/media/media.lawrence.com/static/" | |
STATIC_ROOT = '' | |
# URL prefix for static files. | |
# Example: "http://media.lawrence.com/static/" | |
STATIC_URL = '/static/' | |
# Additional locations of static files | |
STATICFILES_DIRS = ( | |
# Put strings here, like "/home/html/static" or "C:/www/django/static". | |
# Always use forward slashes, even on Windows. | |
# Don't forget to use absolute paths, not relative paths. | |
) | |
# List of finder classes that know how to find static files in | |
# various locations. | |
STATICFILES_FINDERS = ( | |
'django.contrib.staticfiles.finders.FileSystemFinder', | |
'django.contrib.staticfiles.finders.AppDirectoriesFinder', | |
# 'django.contrib.staticfiles.finders.DefaultStorageFinder', | |
) | |
# Make this unique, and don't share it with anybody. | |
SECRET_KEY = '&tu0!6cg)s2xvfcxz(8csums6tjsxg#u$wpg$oy43(33^uoc%=' | |
# List of callables that know how to import templates from various sources. | |
TEMPLATE_LOADERS = ( | |
'django.template.loaders.filesystem.Loader', | |
'django.template.loaders.app_directories.Loader', | |
# 'django.template.loaders.eggs.Loader', | |
) | |
MIDDLEWARE_CLASSES = ( | |
'django.middleware.common.CommonMiddleware', | |
'django.contrib.sessions.middleware.SessionMiddleware', | |
'django.middleware.csrf.CsrfViewMiddleware', | |
'django.contrib.auth.middleware.AuthenticationMiddleware', | |
'django.contrib.messages.middleware.MessageMiddleware', | |
# Uncomment the next line for simple clickjacking protection: | |
# 'django.middleware.clickjacking.XFrameOptionsMiddleware', | |
) | |
ROOT_URLCONF = 'hstoredyn.urls' | |
# Python dotted path to the WSGI application used by Django's runserver. | |
WSGI_APPLICATION = 'hstoredyn.wsgi.application' | |
TEMPLATE_DIRS = ( | |
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". | |
# Always use forward slashes, even on Windows. | |
# Don't forget to use absolute paths, not relative paths. | |
"/Users/iuri/Sources/GITHUB/hstoredyn/templates" | |
) | |
INSTALLED_APPS = ( | |
'django.contrib.auth', | |
'django.contrib.contenttypes', | |
'django.contrib.sessions', | |
'django.contrib.sites', | |
'django.contrib.messages', | |
'django.contrib.staticfiles', | |
# Uncomment the next line to enable the admin: | |
'django.contrib.admin', | |
# Uncomment the next line to enable admin documentation: | |
'django.contrib.admindocs', | |
'hstoredyn' | |
) | |
# A sample logging configuration. The only tangible logging | |
# performed by this configuration is to send an email to | |
# the site admins on every HTTP 500 error when DEBUG=False. | |
# See http://docs.djangoproject.com/en/dev/topics/logging for | |
# more details on how to customize your logging configuration. | |
LOGGING = { | |
'version': 1, | |
'disable_existing_loggers': False, | |
'filters': { | |
'require_debug_false': { | |
'()': 'django.utils.log.RequireDebugFalse' | |
} | |
}, | |
'handlers': { | |
'mail_admins': { | |
'level': 'ERROR', | |
'filters': ['require_debug_false'], | |
'class': 'django.utils.log.AdminEmailHandler' | |
} | |
}, | |
'loggers': { | |
'django.request': { | |
'handlers': ['mail_admins'], | |
'level': 'ERROR', | |
'propagate': True, | |
}, | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.conf.urls import patterns, include, url | |
# Uncomment the next two lines to enable the admin: | |
from django.contrib import admin | |
admin.autodiscover() | |
urlpatterns = patterns('', | |
# Examples: | |
# url(r'^$', 'hstoredyn.views.home', name='home'), | |
# url(r'^hstoredyn/', include('hstoredyn.foo.urls')), | |
# Uncomment the admin/doc line below to enable admin documentation: | |
url(r'^admin/doc/', include('django.contrib.admindocs.urls')), | |
url(r'^hstoredyn/$', 'hstoredyn.views.index'), | |
url(r'^hstoredyn/add$', 'hstoredyn.views.add'), | |
url(r'^hstoredyn/(?P<some_id>\d+)/$', 'hstoredyn.views.detail'), | |
# Uncomment the next line to enable the admin: | |
url(r'^admin/', include(admin.site.urls)), | |
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' | |
Created on 13/10/2012 | |
@author: iuri | |
''' | |
from django.template import Context, loader | |
from hstoredyn.models import Something | |
from django.http import HttpResponse | |
from django.http import HttpResponseRedirect | |
from django.shortcuts import render | |
from hstoredyn.models import SomethingForm | |
def index(request): | |
somethings = Something.objects.all() | |
t = loader.get_template('something/index.html') | |
c = Context({ | |
'somethings_list': somethings, | |
}) | |
return HttpResponse(t.render(c)) | |
def detail(request, some_id): | |
return HttpResponse("You're looking at something %s." % some_id) | |
def add(request): | |
if request.method == 'POST': # If the form has been submitted | |
form = SomethingForm(request.POST) # A form bound to the POST data | |
if form.is_valid(): # All validation rules pass | |
# Process the data in form.cleaned_data | |
# ... | |
form.save() | |
return HttpResponseRedirect('/thanks/') # Redirect after POST | |
else: | |
form = SomethingForm() # An unbound form | |
#form.as_p() | |
return render(request, 'something/add.html', { | |
'form': form, | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
WSGI config for hstoredyn project. | |
This module contains the WSGI application used by Django's development server | |
and any production WSGI deployments. It should expose a module-level variable | |
named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover | |
this application via the ``WSGI_APPLICATION`` setting. | |
Usually you will have the standard Django WSGI application here, but it also | |
might make sense to replace the whole Django WSGI application with a custom one | |
that later delegates to the Django one. For example, you could introduce WSGI | |
middleware here, or combine a Django application with an application of another | |
framework. | |
""" | |
import os | |
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "hstoredyn.settings") | |
# This application object is used by any WSGI server configured to use this | |
# file. This includes Django's development server, if the WSGI_APPLICATION | |
# setting points here. | |
from django.core.wsgi import get_wsgi_application | |
application = get_wsgi_application() | |
# Apply WSGI middleware here. | |
# from helloworld.wsgi import HelloWorldApplication | |
# application = HelloWorldApplication(application) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment