Django CreateView не сохраняет объект

Я пытаюсь использовать класс Create View в приложении Django, но не могу сохранить объект. Я попробовал несколько предложений, опубликованных в связанных вопросах здесь и здесь безрезультатно.

Ошибка

NoReverseMatch в /metas/add-meta Обратное для 'metas_detalle' с аргументами '()' и аргументами ключевого слова '{'pk': None}' не найдено. Пробовали 1 шаблон(ы): ['metas/(?P\d+)/control$']

Форма рабочая и валидная, класс вызывает метод save(), но объект не сохраняется, поэтому id равно None.

Это мой models.py:

class MetasSPE(models.Model):
    puesto = models.CharField("Cargo", max_length=6, choices=PUESTOS)
    clave = models.CharField("Clave de la Meta", max_length=2)
    nom_corto = models.CharField('Identificación', max_length=25)
    year = models.PositiveIntegerField("Año")
    evaluacion = models.BooleanField('Evaluación', default=True)
    ciclos = models.PositiveSmallIntegerField('Repeticiones')
    descripcion = models.TextField('Descripción de la Meta')
    descripcion_html = models.TextField(
        'Descripción de la Meta', editable=False)
    soporte = models.FileField(
        'Soporte', upload_to=archivo_soporte, blank=True, null=True)
    usuario = models.ForeignKey(User, related_name='meta_user', editable=False)
    creacion = models.DateTimeField(auto_now_add=True)
    actualiza = models.DateTimeField(auto_now=True)

    def get_absolute_url(self):
        from django.core.urlresolvers import reverse
        return reverse('metas_detalle', kwargs={'pk': self.id})

get_absolute_url() работает, проверено в python manage.py shell:

In [1]: from django.core.urlresolvers import reverse

In [2]: reverse('metas_detalle', kwargs={'pk': 1})
Out[2]: '/metas/1/control'

Это forms.py:

class MetasSPEForm(forms.ModelForm):
    class Meta:
        model = MetasSPE
        fields = ("puesto", "clave", "nom_corto", "evaluacion", "ciclos", "descripcion", "soporte")

А это мой views.py:

class CrearMeta(CreateView):
    model = MetasSPE
    form_class = MetasSPEForm
    template_name = 'metas/form_base.html'

    def form_valid(self, form):
        form.instance.usuario = self.request.user
        form.instance.year = 2015
        return super(CrearMeta, self).form_valid(form)

urls.py выглядит так:

urlpatterns = patterns(
    'metas.views',
    url(r'^$', 'home', name='metas_index'),

    url(r'^(?P<pk>\d+)/control$', MetaDetalle.as_view(), name='metas_detalle'),
    url(r'^add-meta$', 'agregar_meta', name='metas_add'),
)

Кстати, я попробовал эту функцию и получил точно такую ​​же ошибку, но не могу понять причину:

# from annoying.decorators import render_to
# from django.contrib.auth.decorators import login_required

@login_required
@render_to('metas/form_base.html')
def agregar_meta(request):
    if request.method == 'POST':
        form = MetasSPEForm(request.POST, request.FILES)
        if form.is_valid():
            meta = form.save(commit=False)
            meta.usuario = request.user
            meta.year = 2015
            meta.save()
            return redirect('metas_detalle', kwargs={'pk': meta.id})
    else:
        form = MetasSPEForm()
    return {'title': 'Agregar nueva meta', 'form': form}

Надеюсь, вы можете мне помочь.


person toledano    schedule 27.05.2015    source источник
comment
Пожалуйста, покажите нам код шаблона, который вы используете для формы.   -  person Michael B    schedule 27.05.2015
comment
Вот мой шаблон: gist.github.com/jstoledano/0ff6800f8e018e8da32f. Я использую materializecss.com   -  person toledano    schedule 27.05.2015


Ответы (1)


Согласно ошибке, у вас определен следующий шаблон URL:

metas/(?P\d+)/control$

...который должен быть metas/(?P<pk>\d+)/control$

Обратите внимание, что это отличается от приведенных выше шаблонов:

urlpatterns = patterns(
    'metas.views',
    url(r'^$', 'home', name='metas_index'),

    url(r'^(?P<pk>\d+)/control$', MetaDetalle.as_view(), name='metas_detalle'),
    url(r'^add-meta$', 'agregar_meta', name='metas_add'),
)

Если бы мне пришлось угадывать, вы делаете что-то вроде приведенного ниже в корневом каталоге urls.py:

urlpatterns = patterns(
    '',
    url(r'^metas/', include('metas.urls')),
    # Bad line with bad regex below!
    url(r'metas/(?P\d+)/control$', MetaDetalle.as_view(), name='metas_detalle'),
)

Собственно, нашел проблему:

https://github.com/SGC-Tlaxcala/sgc-metas/blob/e5a6c8e7a54f833795c46d5ece438b219460bf47/src/metas/models.py#L167-L177

class MetasSPE(models.Model):
    ...
    def save(self, **kwargs):
        """
        Se sobre-escribe el método `save()` para guardar la descripción con html.
        :param kwargs: Parámetros en clave
        :return: nada
        """
        from markdown import markdown
        self.descripcion_html = markdown(
            self.descripcion, outpu_format='html5', lazy_ol=True
        )

    def __str__(self):
        ...

Вы забыли вызвать super() в переопределенном методе save(), что означает, что ваша модель никогда не сохранится:

class MetasSPE(models.Model):
    ...
    def save(self, **kwargs):
        """
        Se sobre-escribe el método `save()` para guardar la descripción con html.
        :param kwargs: Parámetros en clave
        :return: nada
        """
        from markdown import markdown
        self.descripcion_html = markdown(
            self.descripcion, outpu_format='html5', lazy_ol=True
        )
        super(MetasSPE, self).save(**kwargs)
person Michael B    schedule 27.05.2015
comment
Извините, это urls.py проекта: gist.github.com/jstoledano/0e535b324fa402c19d28 - person toledano; 27.05.2015
comment
Ваше решение выложено выше в правке - проблема была в не выложенном коде. Я нашел его через вашу учетную запись github. Вы переопределили метод save() в модели, но никогда не вызывали его повторно через super(). Поэтому экземпляр модели никогда не будет сохранен. - person Michael B; 27.05.2015
comment
Большое спасибо, @Michael-B, это была проблема. - person toledano; 27.05.2015