首页 文章

超出最大递归深度,保存方法,Django

提问于
浏览
1

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

起初我使用了io.StringIO,我得到了一个字符串参数,得到'bytes'错误信息 . 所以我随后将io.StringIO更改为io.BytesIO . 然后我得到另一个错误'_io.BytesIO'对象没有属性'len'所以为了获得对象的长度我使用了buffer.getbuffer() . nbytes但是现在我得到了超出的最大递归深度并且它生成了298个QR码图像而不只是一个 . 我有什么想法我做错了吗?

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)

-------------------- SOLUTION UPDATE ---------------------------- ---

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

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)

2 回答

  • 2

    self.qrcode.save 表示需要保存整个模型对象,因此它会调用 save 调用 generate_qrcode ,调用 self.qrcode.save ...(顺便说一下,你应该能够在回溯中看到这个),所以你的问题没什么做 BytesIO . 在某处插入条件以打破递归循环 .

  • 0

    okey这里是我对models.Model的完整解决方案,他们使用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
    

    只是它,帮助的好处 .

相关问题