hovel / pybbm

Django forum solution. Tested, documented, shipped with example project.
BSD 2-Clause "Simplified" License
225 stars 151 forks source link

'Transaction managed block ended with pending COMMIT/ROLLBACK' #33

Closed ckcollab closed 11 years ago

ckcollab commented 11 years ago

For some reason when I try to add a post, I'm getting this error. I can't figure out why, but it must not be successful for some reason:

class PostEditMixin(object):

    def get_form_class(self):
        if self.request.user.is_staff:
            return AdminPostForm
        else:
            return PostForm

    def get_context_data(self, **kwargs):
        ctx = super(PostEditMixin, self).get_context_data(**kwargs)
        if defaults.PYBB_ATTACHMENT_ENABLE and (not 'aformset' in kwargs):
            ctx['aformset'] = AttachmentFormSet(instance=self.object if getattr(self, 'object') else None)
        if 'pollformset' not in kwargs:
            ctx['pollformset'] = PollAnswerFormSet(instance=self.object.topic if getattr(self, 'object') else None)
        return ctx

    def form_valid(self, form):
        success = True
        with transaction.commit_manually():
            self.object = form.save()

            if defaults.PYBB_ATTACHMENT_ENABLE:
                aformset = AttachmentFormSet(self.request.POST, self.request.FILES, instance=self.object)
                if aformset.is_valid():
                    aformset.save()
                else:
                    success = False
            else:
                aformset = AttachmentFormSet()

            if self.object.topic.poll_type != Topic.POLL_TYPE_NONE and self.object.topic.head == self.object:
                pollformset = PollAnswerFormSet(self.request.POST, instance=self.object.topic)
                if pollformset.is_valid():
                    pollformset.save()
                else:
                    success = False
            else:
                self.object.topic.poll_question = None
                self.object.topic.save()
                self.object.topic.poll_answers.all().delete()
                pollformset = PollAnswerFormSet()

            if success:
                transaction.commit()
                return super(ModelFormMixin, self).form_valid(form)
            else:
                transaction.rollback()
                return self.render_to_response(self.get_context_data(form=form, aformset=aformset, pollformset=pollformset))

Here's my error:

TransactionManagementError at /forum/forum/1/topic/add/
Transaction managed block ended with pending COMMIT/ROLLBACK

Let me know if I need to get more specific, I don't really know what else I could have done wrong.

GeyseR commented 11 years ago

Can you post what data do you enter in form and your PYBBM-* settings? I'll try to reproduce this error

ckcollab commented 11 years ago

Im at home now, no special settings and any valid input seems to make this happen.

It's definitely my fault, i just don't know what's broken.

Ill update tomorrow with as many details as i can. I tried flush then syncdb --migrate with no success

GeyseR commented 11 years ago

Try to add post any kind of data: with poll, without poll, try to disable attachments or post invalid data Check that error reproduces from all kinds of input data I will be wait your results

ckcollab commented 11 years ago

Settings

PYBB_ATTACHMENT_ENABLE = True
ACCOUNT_ACTIVATION_DAYS = 1
PYBB_DEFAULT_AUTOSUBSCRIBE = False

Any input doesn't work.

GeyseR commented 11 years ago

Please, try to comment this line:

with transaction.commit_manually():

I suppose, that django swallows some exception, which raises inside this block

ckcollab commented 11 years ago

Alright, did that now:

ValidationError at /forum/forum/1/topic/add/
[u'ManagementForm data is missing or has been tampered with']

Appreciate your quick responses, you are running a great project!

EDIT: More details

aformset = AttachmentFormSet(self.request.POST, self.request.FILES, instance=self.object) ...
▼ Local vars
self    = <pybb.views.AddPostView object at 0x0000000003F4F710>
form    = <pybb.forms.AdminPostForm object at 0x0000000003DAD828>
success = True
ckcollab commented 11 years ago

Actually, the post is in the forums, but I DID get that error anyway! :)

zeus commented 11 years ago

Looks like something wrong with attachments management form (in attachments formset), can you show POST request that your browser sent to django?

ckcollab commented 11 years ago
body    u'Test body'
poll_answers-1-id   u''
poll_answers-TOTAL_FORMS    u'2'
name    u'Test subject'
poll_answers-MAX_NUM_FORMS  u'10'
poll_answers-1-text u''
poll_question   u''
poll_answers-0-id   u''
poll_answers-INITIAL_FORMS  u'0'
poll_answers-0-text u''
login   u'eric'
poll_type   u'0'
csrfmiddlewaretoken u'blehblahabhabh valid'

I garbled up the csrf token, that's all the POST data.

ValidationError at /forum/forum/1/topic/add/
[u'ManagementForm data is missing or has been tampered with']
            aformset = AttachmentFormSet(self.request.POST, self.request.FILES, instance=self.object) ...

self    <pybb.views.AddPostView object at 0x000000000434F4A8>
form    <pybb.forms.AdminPostForm object at 0x000000000434D0B8>
success True
ckcollab commented 11 years ago

This could have something to do with it, I do

manage.py dumpdata > please_dear_god_work.json

Then in my test environment, that fixture says:

IntegrityError: Could not load contenttypes.ContentType(pk=18): duplicate key value violates unique constraint "django_content_type_app_label_model_ke
y"
DETAIL:  Key (app_label, model)=(pybb, attachment) already exists.

(this is after deleting database, doing manage.py syncdb --migrate and starting from scratch)

GeyseR commented 11 years ago

@ckcollab, can you post here whole html, that produced by "topic add" page? Attachments management form inserted in pybb/attachments_formset.html template. Did you override or change it?

ckcollab commented 11 years ago

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/html">
<head>
    <meta charset="utf-8">
    <title> - LoLKarma - Forget the baddies</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="">
    <meta name="author" content="">

    <!-- Le styles -->
    <link href="/static/css/bootstrap.min.css" rel="stylesheet">
    <link href="/static/css/bootstrap-responsive.css" rel="stylesheet">
    <link href="/static/django_tables2/themes/paleblue/css/screen.css" rel="stylesheet">
    <link href="/static/css/custom.css" rel="stylesheet">

    <!-- Le fav and touch icons -->
    <link rel="shortcut icon" href="../assets/ico/favicon.ico">
</head>

<script type="text/javascript">
    var RecaptchaOptions = {
        theme: 'custom',
        custom_theme_widget: 'recaptcha_widget'
    };
</script>

<body>

<div id="header_container" class="navbar navbar-inverse navbar-fixed-top">
    <div class="navbar-inner">
        <div id="header" class="container">
            <a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </a>

            <div id="header_form" class="row padding">
                <div class="offset7 span5">
                    <form id="search_form" class="navbar-form pull-right">
                        <input id="player_search_name" type="text" placeholder="Search for name" data-provide="typeahead">
                        <select id="player_search_region" class="input-medium">
                            <option value="lol_na_">LoL - NA</option>
                            <option value="lol_eu_">LoL - EU</option>
                            <option value="lol_as_">LoL - Asia</option>
                        </select>
                        <a href="javascript:search()" class="btn"><i class="icon-circle-arrow-right"></i></a>
                    </form>
                </div>

                <div id="header_login_link" class="pull-right">

                        'ello eric, you can <a href="/accounts/profile/">edit your profile</a> or <a href="/accounts/logout/">logout</a>!

                </div>

            </div>

            <div class="nav-collapse collapse offset2">
                <ul class="nav">
                    <li><a href="/">Home</a></li>
                    <li><a href="/tour/">Tour</a></li>
                    <li><a href="#">FAQ</a></li>
                    <li><a href="/browse/?sort=-karma">Browse</a></li>
                    <li><a href="/forum/">Forums</a></li>
                    <li><a href="/contact/">Contact</a></li>
                </ul>
            </div><!--/.nav-collapse -->
        </div>
    </div>

    <div id="breadcrumb_holder">
        <div class="container">
            <div class="span10">

<a href="/">Home</a> &raquo;

            <a href="/forum/category/1/">GG Gamers</a> &raquo;

        <a href="/forum/forum/1/">Suggestions</a> &raquo;

    New topic

<!--
<ul class='breadcrumb'>

        <li><a href="/">Home</a> <span class="divider">/</span></li>

                <li><a href="/forum/category/1/">GG Gamers</a> <span class="divider">/</span></li>

            <li><a href="/forum/forum/1/">Suggestions</a> <span class="divider">/</span></li>

        <li>New topic</li>

</ul>
-->

            </div>
        </div>
    </div>
</div>

<div id="main" class="container">

<h1>New topic</h1>

<form class="post-form" action="

        /forum/forum/1/topic/add/
    " method="post" enctype="multipart/form-data">
  <div style='display:none'><input type='hidden' name='csrfmiddlewaretoken' value='23751d831e6ada08b7e362ca11a94f6d' /></div>
  <fieldset>

      <label for="id_name">Subject</label> <input type="text" name="name" id="id_name" /> 
      <label for="id_login">User</label> <input type="text" name="login" value="eric" id="id_login" />  

        <label for="id_body">Message</label> 
        <textarea id="id_body" rows="10" cols="40" name="body" class="span8"></textarea>  

    <div id='emoticons'>

        <a href='#' title='8)'><img src='/static/pybb/emoticons/glasses.png'></a>

        <a href='#' title=':('><img src='/static/pybb/emoticons/sad.png'></a>

        <a href='#' title=':)'><img src='/static/pybb/emoticons/smile.png'></a>

        <a href='#' title='&gt;_&lt;'><img src='/static/pybb/emoticons/angry.png'></a>

        <a href='#' title=';)'><img src='/static/pybb/emoticons/wink.png'></a>

        <a href='#' title=':O'><img src='/static/pybb/emoticons/shok.png'></a>

        <a href='#' title='-_-'><img src='/static/pybb/emoticons/shy.png'></a>

        <a href='#' title='[]_[]'><img src='/static/pybb/emoticons/geek.png'></a>

        <a href='#' title=':D'><img src='/static/pybb/emoticons/lol.png'></a>

        <a href='#' title=':.('><img src='/static/pybb/emoticons/cry.png'></a>

        <a href='#' title='o_O'><img src='/static/pybb/emoticons/eyes.png'></a>

        <a href='#' title=':P'><img src='/static/pybb/emoticons/tongue.png'></a>

    </div>

 <label for="id_poll_type">Poll type</label> <select name="poll_type" id="id_poll_type">
<option value="0">None</option>
<option value="1">Single answer</option>
<option value="2">Multiple answers</option>
</select>
<div id="poll-answers-formset" style="display: none;">
   <label for="id_poll_question">Poll question</label> <textarea id="id_poll_question" rows="10" cols="40" name="poll_question" class="no-markitup"></textarea>
  <br>Poll answers

  <table>

      <tr>
        <td><input type="hidden" name="poll_answers-0-id" id="id_poll_answers-0-id" /> <input id="id_poll_answers-0-text" type="text" name="poll_answers-0-text" maxlength="255" /></td>
        <td></td>
      </tr>

      <tr>
        <td><input type="hidden" name="poll_answers-1-id" id="id_poll_answers-1-id" /> <input id="id_poll_answers-1-text" type="text" name="poll_answers-1-text" maxlength="255" /></td>
        <td></td>
      </tr>

  </table>
  <input type="hidden" name="poll_answers-TOTAL_FORMS" value="2" id="id_poll_answers-TOTAL_FORMS" /><input type="hidden" name="poll_answers-INITIAL_FORMS" value="0" id="id_poll_answers-INITIAL_FORMS" /><input type="hidden" name="poll_answers-MAX_NUM_FORMS" value="10" id="id_poll_answers-MAX_NUM_FORMS" />
</div>

<script type="text/javascript">
  window.onload = function () {
    $('div#poll-answers-formset table tr').formset({
      deleteText:'remove answer',
      addText:'add answer',
      prefix: 'poll_answers'
    });

    var toggle_poll_answers_formset = function (poll_type) {
      if (poll_type == 0) {
        $('div#poll-answers-formset').hide();
      } else {
        $('div#poll-answers-formset').show();
      }
    };

    $('#id_poll_type').each(function () {
      toggle_poll_answers_formset($(this).val());
    }).change(function () {
      toggle_poll_answers_formset($(this).val());
    });
  };
</script>

    <p class="submit"><input type="submit" class="btn btn-primary" value="Submit" /></p>
  </fieldset>
</form>

</div>

<footer>
    <div class="container">
        <div class="span5">
            Contact us
        </div>

        <p>&copy; CK Collab LLC 2012. League of Legends is a registered trademark of Riot Games Inc.</p>
    </div>
</footer>

<!-- Le javascript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="/static/js/jquery.js"></script>
<script src="/static/js/bootstrap.js"></script>
<script src="/static/pybb/js/pybbjs.js"></script>
<script src="/static/pybb/js/jquery.formset.min.js"></script>

<script type="text/javascript">
    $(document).ready(function(){
        // Apply active class to li parent of a
        $('a[href="' + getUrlPath() + '"]').each(function(index, anchor){
            $(anchor).parent().addClass('active');
        });

        $('#player_search_name').typeahead({
            source: function (query, process) {
                return $.get('/playerlookup', { query: 'lol_na_' + query }, function (data) {
                    return process(data);
                });
            }
        });
    });

    function getUrlPath() {
        // in the case that we're on the home page, return /
        if(window.location.pathname.split('/')[1] == ''){
            return '/';
        }

        // otherwise return the good oooooooold url
        return '/' + window.location.pathname.split( '/' )[1] + '/';
    }

    function search() {
        hostAddress= top.location.host.toString();
        url = 'http://' + hostAddress + '/player/' + $('#player_search_region').val() + $('#player_search_name').val() + '/';

        window.location = url;
    }
</script>
</body>
</html>

That's the whole page! Couldn't see anything about attachments in there, hrm...

ckcollab commented 11 years ago
PYBB_ATTACHMENT_ENABLE = False

And it works now...

#pybb/views.py line 202ish
        if defaults.PYBB_ATTACHMENT_ENABLE:
            aformset = AttachmentFormSet(self.request.POST, self.request.FILES, instance=self.object)
            if aformset.is_valid():
                aformset.save()
            else:
                success = False
        else:
            aformset = AttachmentFormSet()

Hrm...

GeyseR commented 11 years ago

Check that you added

'pybb.context_processors.processor'

in your CONTEXT_PROCESSORS setting as said in docs

ckcollab commented 11 years ago

Yessir

CONTEXT_PROCESSORS = (
    'pybb.context_processors.processor',
    )
GeyseR commented 11 years ago

Sorry, but we can't debug every step with you. Your problem is that attachments form doesn't render in html when PYBB_ATTACHMENT_ENABLE = True, but it must. This setting included in context there, next attachments template included on post add form there and finally rendered there. You have problem on one of these steps.

ckcollab commented 11 years ago

Thanks, PYBB_ATTACHMENT_ENABLE = False makes it work fine,thanks.

ghost commented 11 years ago

I have problem with transaction too. Error appears only with enabled attachments and post with attachment.

GeyseR commented 11 years ago

What kind of proplem do you have, can you provide stack of error? First of all check your version of pybbm, problem with transactions was fixed in 0.12 version

ghost commented 11 years ago

Oh, sorry. Problem have solved by version upgrade. Thanks!