【问题标题】:Maximum recursion depth exceeded, save method, Django超出最大递归深度,保存方法,Django
【发布时间】:2016-09-24 22:42:36
【问题描述】:

尝试使用 Python3.4 使用 QR-code 5.3 生成 QR 码时。我遇到了几个问题:

起初我使用了 io.StringIO,我得到了一个 字符串参数,得到了 'bytes' 错误消息。所以我随后将 io.StringIO 更改为 io.BytesIO。然后我得到另一个错误是 '_io.BytesIO' object has no attribute 'len' 所以为了得到我使用的对象的长度 buffer.getbuffer().nbytes em> 但现在我得到了最大递归深度超出,它生成了 298 个二维码图像,而不仅仅是一个。任何想法我做错了什么?

from django.db import models
from django.conf import settings
from django.core.urlresolvers import reverse
from django.core.files.uploadedfile import InMemoryUploadedFile

import random
import qrcode
import io
import sys

from PIL import Image

import pdb;


def qrcode_location(instance, filename):
    return '%s/qr_codes/%s' % (instance.user.username, filename)


# Create your models here.
class EmployeeProfile(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL,  on_delete=models.CASCADE)
    qrcode = models.ImageField(upload_to=qrcode_location, null=True, blank=True)
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

    def __str__(self):
        return self.first_name + ' ' + self.lastname

    def save(self):
        first_initial = self.first_name[0].upper()
        second_initial = self.last_name[0].upper()
        id_number = first_initial + second_initial + str(random.randint(1000000, 9999999))
        self.generate_qrcode()

        if not EmployeeProfile.objects.filter(employee_id=id_number).exists():
            self.employee_id = id_number
            super(EmployeeProfile, self).save()

    def generate_qrcode(self):
        qr = qrcode.QRCode(
            version=1,
            error_correction=qrcode.constants.ERROR_CORRECT_L,
            box_size=10,
            border=4,
        )
        qr.add_data('Some data')
        qr.make(fit=True)

        img = qr.make_image()

        buffer = io.BytesIO()
        img.save(buffer)
        filename = 'qrcode.png'
        filebuffer = InMemoryUploadedFile(buffer, None, filename, 'image/png', buffer.getbuffer().nbytes, None)
        self.qrcode.save(filename, filebuffer)

--------解决方案更新------------------------- ------

由于 save 调用了 generate_qrcode,并且调用了 self.qrcode.save 并且模型调用了 save 导致无限递归。因此,为了防止您只需要通过为 FileField 的保存方法提供额外的第三个参数来绕过它。

Django FileField in model maximum recursion depth exceeded while calling a Python object

# set 3 argument to false(save=False) otherwise infinite recursion will happen
self.qrcode.save(filename, filebuffer, False)

【问题讨论】:

  • 当您单步执行pdb 时会发生什么?此外,这是在黑暗中刺伤,但是如果您删除 self.qrcode.save,递归会消失吗?
  • 删除super(EmployeeProfile, self).save()后会发生什么变化?
  • @AlexHall,是的,当我删除 self.qrcode.save 时,递归确实消失了,但是它不会保存生成的图像。
  • @Keiwan,没什么变化,结果还是一样

标签: python django


【解决方案1】:

self.qrcode.save 表示需要保存整个模型对象,因此会导致调用save 调用generate_qrcode 调用self.qrcode.save...(顺便说一下,您应该可以看到这在回溯中)所以你的问题与BytesIO无关。在某处插入条件以中断递归循环。

【讨论】:

【解决方案2】:

这里是我对模型的完整解决方案。模型使用 slug 字段以及 get_absolute_url 和 qr_code

class Posts(models.Model):
    slug = models.SlugField(unique=True)
    title = models.CharField(max_length=30)
    my_qrcode = models.ImageField(upload_to='qrCode', null=True, blank=True)

    def save(self, *args, **kwargs):
        # we override the save method other wise, slug will not be effect and get_absolute_url will not work
        if self.slug:
            pass # here prevents to create slug again when updating your posts
        else:
            self.generate_qrcode()
        super(Posts,self).save(*args, **kwargs)

    def get_absolute_url(self):
        return reverse('posts:detail', kwargs={'slug':self.slug})

    def generate_qrcode(self):
        # this part creates unique slugs
        slug = slugify(self.title)
        while self.__class__.objects.filter(slug=slug).order_by('-id').exists():
            qs = self.__class__.objects.filter(slug=slug).order_by('-id')
            new_slug = '%s-%s' % (slug, qs.first().id)
            slug = new_slug
        self.slug = slug

        qr = qrcode.QRCode(
            version=1,
            error_correction=qrcode.constants.ERROR_CORRECT_L,
            box_size=6,
            border=0,
        )
        qr.add_data(self.get_absolute_url())
        qr.make(fit=True)

        img = qr.make_image()

        buffer = StringIO.StringIO()
        img.save(buffer)
        filename = 'QrCode-%s.png' % (slug)
        filebuffer = InMemoryUploadedFile(buffer, None, filename, 'image/png', buffer.len, None)
        self.my_qrcode.save(filename, filebuffer, False) # we already have save method so just make False itself save behavior

只是它,帮助的好处。

【讨论】:

    猜你喜欢
    • 2017-08-09
    • 2011-03-31
    • 2013-02-20
    • 1970-01-01
    • 2013-12-01
    • 2011-09-19
    • 2019-01-18
    • 2013-03-03
    相关资源
    最近更新 更多