Permalink
Browse files

casper

  • Loading branch information...
1 parent 143de08 commit fcfae33d402c1cb7022bd2c924f62b1cb8430496 @saxix committed Dec 28, 2013
View
@@ -2,7 +2,7 @@
branch = True
source = adminactions
include =
- adminactions/**
+ tests/**
omit = adminactions/__init__.py
adminactions/tests/**
View
@@ -2,6 +2,9 @@ language: python
python:
- "2.7"
+branches:
+ only:
+ - feature/casper
env:
- DJANGO="1.4.x" DBENGINE=pg
- DJANGO="1.5.x" DBENGINE=pg
@@ -13,10 +16,13 @@ install:
- python setup.py -q install
script:
- - make ci
+ - make init-db ci
before_script:
- make init-db
+ - "export DISPLAY=:99.0"
+ - sleep 5
+ - "export PHANTOMJS_EXECUTABLE='phantomjs --local-to-remote-url-access=yes --ignore-ssl-errors=yes'"
after_success:
- coveralls -c .coveragerc
View
@@ -17,8 +17,6 @@ mkbuilddir:
test:
py.test
-selenium:
- cd demo && ./manage.py test adminactions
locale:
cd adminactions && django-admin.py makemessages -l en
@@ -47,7 +45,7 @@ ci: init-db
@python -c "from __future__ import print_function;import django;print('Django version:', django.get_version())"
@echo "Database:" ${DBENGINE}
- @pip install -r adminactions/requirements/install.pip -r adminactions/requirements/testing.pip
+ @pip install -r adminactions/requirements/testing.pip
DISABLE_SELENIUM=1 $(MAKE) coverage
View
@@ -47,7 +47,9 @@ def merge(master, other, fields=None, commit=False, m2m=None, related=None):
@return:
"""
- fields = fields or [f.name for f in master._meta.fields]
+ if fields is None:
+ fields = [f.name for f in master._meta.fields]
+
all_m2m = {}
all_related = {}
@@ -66,7 +68,7 @@ def merge(master, other, fields=None, commit=False, m2m=None, related=None):
for fieldname in fields:
f = get_field_by_path(master, fieldname)
- if not f.primary_key:
+ if f and not f.primary_key:
setattr(result, fieldname, getattr(other, fieldname))
if m2m:
@@ -97,7 +99,6 @@ def merge(master, other, fields=None, commit=False, m2m=None, related=None):
if commit:
for name, elements in all_related.items():
- # dest = getattr(result, name)
for rel_fieldname, element in elements:
setattr(element, rel_fieldname, master)
element.save()
@@ -7,5 +7,6 @@ class ActionInterrupted(Exception):
to prevent action to be executed
"""
+
class FakeTransaction(Exception):
pass
@@ -101,7 +101,7 @@ def graph_queryset(modeladmin, request, queryset):
xaxis: {pad: 1.05,
tickOptions: {formatString: '%%d'}}
}
- }""" % (json.dumps(data_labels), json.dumps(data_labels))
+ }""" % (json.dumps(data_labels), json.dumps(data_labels))
elif graph_type == 'PieChart':
table = [zip(data_labels, data)]
extra = """{seriesDefaults: {renderer: jQuery.jqplot.PieRenderer,
@@ -111,7 +111,6 @@ def graph_queryset(modeladmin, request, queryset):
lineWidth: 5}},
legend: {show: true, location: 'e'}}"""
-
except Exception as e:
messages.error(request, 'Unable to produce valid data: %s' % str(e))
else:
@@ -106,7 +106,7 @@ def __getitem__(self, field_class):
class MassUpdateForm(GenericActionForm):
- _no_sample_for =[]
+ _no_sample_for = []
_clean = forms.BooleanField(label='clean()',
required=False,
help_text="if checked calls obj.clean()")
View
@@ -3,7 +3,6 @@
from django.contrib import messages
from django.contrib.admin import helpers
from django import forms
-from adminactions import transaction
from django.forms import TextInput, HiddenInput
from django.forms.formsets import formset_factory
from django.forms.models import modelform_factory, model_to_dict
@@ -12,10 +11,9 @@
from django.utils.safestring import mark_safe
from django.http import HttpResponseRedirect
from django.utils.translation import gettext as _
-from adminactions.exceptions import FakeTransaction
from adminactions.forms import GenericActionForm
from adminactions.models import get_permission_codename
-from adminactions.utils import clone_instance
+from adminactions.utils import clone_instance, model_supports_transactions
class MergeForm(GenericActionForm):
@@ -36,7 +34,7 @@ class MergeForm(GenericActionForm):
master_pk = forms.CharField(widget=HiddenInput)
other_pk = forms.CharField(widget=HiddenInput)
- field_names = forms.CharField(required=False)
+ field_names = forms.CharField(required=False, widget=HiddenInput)
def action_fields(self):
for fieldname in ['dependencies', 'master_pk', 'other_pk', 'field_names']:
@@ -46,6 +44,12 @@ def action_fields(self):
def clean_dependencies(self):
return int(self.cleaned_data['dependencies'])
+ def clean_field_names(self):
+ return self.cleaned_data['field_names'].split(',')
+
+ def is_valid(self):
+ return super(MergeForm, self).is_valid()
+
class Media:
js = ['adminactions/js/merge.min.js']
css = {'all': ['adminactions/css/adminactions.min.css']}
@@ -71,14 +75,15 @@ def raw_widget(field, **kwargs):
# Allows to specified a custom Form in the ModelAdmin
- # MForm = getattr(modeladmin, 'merge_form', MergeForm)
merge_form = getattr(modeladmin, 'merge_form', MergeForm)
MForm = modelform_factory(modeladmin.model, form=merge_form, formfield_callback=raw_widget)
OForm = modelform_factory(modeladmin.model, formfield_callback=raw_widget)
tpl = 'adminactions/merge.html'
+ transaction_supported = model_supports_transactions(modeladmin.model)
ctx = {
'_selected_action': request.POST.getlist(helpers.ACTION_CHECKBOX_NAME),
+ 'transaction_supported': transaction_supported,
'select_across': request.POST.get('select_across') == '1',
'action': request.POST.get('action'),
'fields': [f for f in queryset.model._meta.fields if not f.primary_key and f.editable],
@@ -88,42 +93,42 @@ def raw_widget(field, **kwargs):
if 'preview' in request.POST:
master = queryset.get(pk=request.POST.get('master_pk'))
- original = clone_instance(master)
other = queryset.get(pk=request.POST.get('other_pk'))
+ original = clone_instance(master)
+
formset = formset_factory(OForm)(initial=[model_to_dict(master), model_to_dict(other)])
- with transaction.commit_manually():
- form = MForm(request.POST, instance=master)
- other.delete()
- form_is_valid = form.is_valid()
- transaction.rollback()
-
- if form_is_valid:
- ctx.update({'original': original})
- tpl = 'adminactions/merge_preview.html'
+ form = MForm(request.POST, instance=master)
+
+ form_is_valid = form.is_valid()
+
+ if not form_is_valid:
+ messages.error(request, form.errors)
+
+ fields = form.cleaned_data['field_names']
+ if form.cleaned_data['dependencies'] == MergeForm.DEP_MOVE:
+ related = api.ALL_FIELDS
else:
- raise Exception(form.errors)
+ related = None
+ api.merge(master, other, fields=fields, commit=False, related=related)
+ ctx.update({'original': original})
+ tpl = 'adminactions/merge_preview.html'
+
elif 'apply' in request.POST:
master = queryset.get(pk=request.POST.get('master_pk'))
other = queryset.get(pk=request.POST.get('other_pk'))
formset = formset_factory(OForm)(initial=[model_to_dict(master), model_to_dict(other)])
- with transaction.commit_manually():
- form = MForm(request.POST, instance=master)
- stored_pk = other.pk
- other.delete()
- ok = form.is_valid()
- transaction.rollback()
- other.pk = stored_pk
- if ok:
+ form = MForm(request.POST, instance=master)
+ form_is_valid = form.is_valid()
+ try:
+ fields = form.cleaned_data['field_names']
if form.cleaned_data['dependencies'] == MergeForm.DEP_MOVE:
related = api.ALL_FIELDS
else:
related = None
- fields = form.cleaned_data['field_names']
api.merge(master, other, fields=fields, commit=True, related=related)
return HttpResponseRedirect(request.path)
- else:
- messages.error(request, form.errors)
-
+ except Exception as e:
+ messages.error(request, e)
else:
try:
master, other = queryset.all()
@@ -1,24 +1,31 @@
-.mergetable{
+.mergetable {
width: 100%;
border: 1px solid black;
}
-.mergetable tr.header th{
+
+.mergetable tr.header th {
font-weight: bold;
text-align: center;
}
-.mergetable td{
+
+.mergetable td {
vertical-align: middle;
border-right: 1px solid #000000;
}
.mergetable .column {
- width: 33%;
+}
+
+.mergetable .origin *, .mergetable .result * {
+ width: 100px;
+ word-wrap: break-word;
}
.mergetable .label {
width: 10%;
font-weight: bold;
}
+
.mergetable .selected {
background-color: #81b10c;
}
@@ -27,7 +34,7 @@
background-color: #f9adaf;
}
-.mergetable input.raw-value{
+.mergetable input.raw-value {
width: 200px;
border: 0px transparent;
background-color: transparent;
@@ -1 +1 @@
-.mergetable{width:100%;border:1px solid black}.mergetable tr.header th{font-weight:bold;text-align:center}.mergetable td{vertical-align:middle;border-right:1px solid #000}.mergetable .column{width:33%}.mergetable .label{width:10%;font-weight:bold}.mergetable .selected{background-color:#81b10c}.mergetable .changed{background-color:#f9adaf}.mergetable input.raw-value{width:200px;border:0 transparent;background-color:transparent;display:none}
+.mergetable{width:100%;border:1px solid black}.mergetable tr.header th{font-weight:bold;text-align:center}.mergetable td{vertical-align:middle;border-right:1px solid #000}.mergetable .origin *,.mergetable .result *{width:100px;word-wrap:break-word}.mergetable .label{width:10%;font-weight:bold}.mergetable .selected{background-color:#81b10c}.mergetable .changed{background-color:#f9adaf}.mergetable input.raw-value{width:200px;border:0 transparent;background-color:transparent;display:none}
@@ -19,22 +19,20 @@
{{ adminform.form.non_field_errors }}
<form method="post">{% csrf_token %}
{% for f in adminform.form.hidden_fields %}{{ f }}{% endfor %}
+ {{ adminform.form.field_names }}
<table>
<tr>
<td>{{ adminform.form.dependencies.label }}</td>
- <td>{{ adminform.form.dependencies }}</td>
- </tr>
- <tr>
- <td>{{ adminform.form.field_names.label }}</td>
- <td>{{ adminform.form.field_names }}</td>
+ <td>{{ adminform.form.dependencies }}
+ {% if not transaction_supported %}
+ <div>Warning: your database does not support transactios. Merge cannot be validated and/or undone</div>
+ {% endif %}</td>
</tr>
</table>
<table class="mergetable">
<tr class="header">
<th>{% trans "Field" %}</th>
<th>{% trans "Master" %} #<span id='master_pk'>{{ master.pk }}</span> ({% trans "This will be preserved" %})
- {# <input type="hidden" value="{{ master.pk }}" name="master-pk">#}
-{# {{ adminform.form.master_pk.value }}#}
</th>
<th><a class="swap" href="#">{% trans "swap" %}</a></th>
<th>{% trans "Result" %}</th>
@@ -49,7 +47,7 @@
<td class="column origin">
{{ formset.0|widget:field.name }}
- <span class="display">{{ master|field_display:field }}</span>
+ <span class="display">{{ master|field_display:field}}</span>
</td>
<td><a class="origin" href="#"> &gt;&gt; </a></td>
@@ -13,4 +13,3 @@ def commit_manually():
except:
from django.db.transaction import commit_manually, rollback
-
@@ -1,5 +1,6 @@
from django.db import models
from django.db.models.query import QuerySet
+from django.db import connections, router
def clone_instance(instance, fieldnames=None):
@@ -216,3 +217,8 @@ def flatten(iterable):
else:
result.append(el)
return list(result)
+
+
+def model_supports_transactions(instance):
+ alias = router.db_for_write(instance)
+ return connections[alias].features.supports_transactions
View
@@ -6,9 +6,11 @@
def pytest_configure(config):
here = os.path.dirname(__file__)
sys.path.insert(0, os.path.join(here, 'demo'))
+ sys.path.insert(0, os.path.join(here, 'webtests'))
if not settings.configured:
- os.environ['DJANGO_SETTINGS_MODULE'] = 'demoproject.settings'
+ os.environ['DJANGO_SETTINGS_MODULE'] = 'tests.settings'
+
def runtests(args=None):
import pytest
@@ -2,11 +2,14 @@
from .models import DemoModel, UserDetail
+class UserDetailModelAdmin(ModelAdmin):
+ list_display = [f.name for f in UserDetail._meta.fields]
+
class DemoModelAdmin(ModelAdmin):
# list_display = ('char', 'integer', 'logic', 'null_logic',)
list_display = [f.name for f in DemoModel._meta.fields]
-site.register(DemoModel)
-site.register(UserDetail)
+site.register(DemoModel, DemoModelAdmin)
+site.register(UserDetail, UserDetailModelAdmin)
@@ -0,0 +1,3 @@
+# -*- coding: utf-8 -*-
+
+from django.utils.translation import gettext as _
Oops, something went wrong.

0 comments on commit fcfae33

Please sign in to comment.