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

时间:2016-05-26 19:06:11

标签: python django

尝试使用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 个答案:

答案 0 :(得分:2)

self.qrcode.save表示需要保存整个模型对象,因此会调用save调用调用generate_qrcode的{​​{1}} ...(按你应该能够在追溯中看到这个的方式)所以你的问题与self.qrcode.save无关。在某处插入一个条件来打破递归循环。

答案 1 :(得分:0)

这里的okey是我的模型的完整解决方案。使用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
只是它,帮助的好处。