向复杂的 Django 视图添加值

Posted

技术标签:

【中文标题】向复杂的 Django 视图添加值【英文标题】:Adding Values to Complex Django View 【发布时间】:2012-07-18 19:37:19 【问题描述】:

我正在尝试从 Photographer 模型中获取值字典以显示在我的表单中。之后,用户将选择一个Photographer,提交表单(连同其他信息),并以Photographer 作为属性创建模型A 的实例。虽然我知道 ModelForms 可以更加友好,但在这种情况下我必须使用 BaseForm:

@login_required
def create_in(request, slug):
    element = get_object_or_404(Element, slug=slug)
    a = A.objects.create(element=element, user=request.user)
    a.save()
    return redirect('CreationEditView', pk=a.pk)

urlconf 将用户发送到 create_in,,用户选择 element 然后重定向到 CreationEditView,,后者使用 Django 通用视图中的 BaseUpdateView 来操作对象:

class EditView(BaseUpdateView):
    model = A
    form_class = AForm
    context_object_name = 'a'
    page = 'edit.html'

    def get_element(self):
        return self.object.element

    def render_to_response(self, context, **response_kwargs):
        element = self.get_element()
        return render_page(self.request, element,
                           self.page, context)

    def get_success_url(self):
        return reverse('view_all')

    def get_context_data(self, **kwargs):
        context = super(EditView, self).get_context_data(**kwargs)
        return context

    def get_queryset(self):
        qs = super(EditView, self).get_queryset()
        return qs.filter(active=True, user=self.request.user)

    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        return super(EditView, self).get(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        self.object = self.get_object()
        return super(EditView, self).post(request, *args, **kwargs)

    @method_decorator(login_required)
    def dispatch(self, request, *args, **kwargs):
        return super(EditView, self).dispatch(request, *args, **kwargs)

class CreationEditView(EditView):
    def get_queryset(self):
        qs = super(EditView, self).get_queryset()
        return qs.filter(active=False, user=self.request.user)

    def get_success_url(self):
        return reverse('create_finished',
                       kwargs=dict(pk=self.object.pk))

    def get_context_data(self, **kwargs):
        context = super(CreationEditView, self).get_context_data(**kwargs)
        context['create'] = True
        return context

然后通过render_page 呈现页面,如下所示:

def render_page(request, element, page, context):
    template_name = element_template_name(element, page)
    try:
        template = get_template(template_name)
    except TemplateDoesNotExist:
        template = get_template('template_location/%s' % page)
    context = RequestContext(request, context)
    return HttpResponse(template.render(context))

如果我的模型是这样的:

class Photographer(models.Model):
    name = models.CharField(max_length=20)
    models = models.ManyToManyField('Model')

class Model(models.Model):
    model = models.CharField(max_length=20, blank=False)
    series = models.ForeignKey('Series', null=True, blank=True)

class A(models.Model):
    user = models.ForeignKey(User)
    photographer = models.ForeignKey('Photographer', blank=True, null=True)
    model = models.ForeignKey('Model', blank=True, null=True)

您将如何从Photographer 获取值以正确集成到视图代码中以便稍后在模板中使用?这些值将成为用户从中选择的下拉表单的一部分。一个使用示例会很有帮助。

感谢您的任何想法。

编辑(添加表格)


class AForm(BaseForm):
    def __init__(self, data=None, files=None, instance=None, auto_id='id_%s',
                 prefix=None, initial=None, error_class=ErrorList,
                 label_suffix=':', empty_permitted=False):

        if not instance:
            raise NotImplementedError("Instance must be provided")

        self.instance = instance
        object_data = self.instance.fields_dict()
        self.declared_fields = SortedDict()
        self.base_fields = fields_for_a(self.instance)

        # if initial was provided, it should override the values from instance
        if initial is not None:
            object_data.update(initial)

        BaseForm.__init__(self, data, files, auto_id, prefix, object_data,
                          error_class, label_suffix, empty_permitted)

        cleaned_data = self.cleaned_data

        # save fieldvalues for self.instance
        fields = field_list(self.instance)

        for field in fields:
            if field.enable_wysiwyg:
                value = unicode(strip(cleaned_data[field.name]))
            else:
                value = unicode(cleaned_data[field.name])

        return self.instance

【问题讨论】:

您的实际问题是什么?我真的不明白你的意思。如果 AForm 是模型 A 的 ModelForm,它应该直接为您提供外键字段,这将是您想要的下拉列表。顺便说一句,如果您不需要更改任何内容,请不要覆盖您的类中的方法。 你为什么这样做:class EditView(BaseUpdateView): 而不是这个:class EditView(UpdateView):?我没有看到有什么原因吗?无论如何,就像@pyriku 说的,我不明白你的问题。尝试编辑您的问题以更好地表达您的问题...` 感谢您的回复。问题实际上只是如何访问数据库中的字段。在 php 中,我会直接查询数据库,然后在我的表单中使用这些值。不知道如何使用 Django 从 ManyToManyField 'Model' 获取值并给出上面的结构......补充信息:AForm 不是模型表单,它使用的是BaseForm,这可能导致了困惑。对此感到抱歉。我添加了上面的表格。意见和建议表示赞赏。谢谢 @pyriku:我已经编辑了问题以充分阐述问题。任何想法表示赞赏。谢谢。 BaseForm?为什么不简单地使用 ModelForm?很抱歉,我不明白你正在处理的那种过于复杂的情况。 【参考方案1】:

我认为您缺少 Django 编程的一个基本方面,即 Django 表单。您应该创建一个类似的表单:

class AForm(forms.Form):
    model = forms.ModelChoiceField(queryset=Model.objects.all())
    photographer = forms.ModelChoiceField(queryset=Photographer.objects.all())

    class Meta:
        model = A
        fields = ('model', 'photographer', )

然后您的创建视图将如下所示:

@login_required
def create_in(request, slug):
    if request.method == 'POST':
        form = AForm(request.POST)
        if form.is_valid():
            instance = form.save(commit=False)
            instance.user = request.user
            return HttpResponseRedirect("/somewhere/")
    else:
        form = AForm()
    return render_to_response('create_in.html',  'form': form , context_instance=context)

很难弄清楚您要做什么,我认为您变得过于棘手,因为我从来不需要扩展 BaseForm 并且我已经完成了许多带有特殊过滤器的表单。通常这些操作如下:

class AForm(forms.Form): 
   def __init__(self, profile, *args, **kwargs):
       super(AForm, self).__init__(*args, **kwargs)
       self.fields['photographer'].queryset = models.Photographer.objects.filter(profilephotographer__profile=profile)

【讨论】:

感谢您的回复。如果我使用 Django 的(BaseForm 类)[github.com/django/django/blob/master/django/forms/forms.py] 生成表单怎么办? 感谢您的回复。使用上面的BaseForm 添加了表单。我想为表单使用forms.Form,但场景比这更复杂,我已经在处理上述结构。感谢您详细说明如何使用通用表单进行构造。任何关于如何集成给定BaseForm 的想法也将不胜感激。谢谢。 再次感谢您的回复@Rob Osborne。我感谢您一直以来的支持。尝试将self.fields[''].queryset 与 BaseForm 一起使用会导致属性错误:object has no attribute 'fields',因为我猜 BaseForm 不支持 fields 属性。我知道使用 BaseForm 有点过时,但我必须为这个项目使用 BaseForm。任何其他关于如何在我的结构化表单中包含额外查询集的想法都值得赞赏。 在 BaseForm 子类中,字段在调用 init 之后才会存在。 根据上面的内容,这一行实际上应该是self.fields['photographer'].queryset = Photographer.objects.all()。请注意这位独特的摄影师。

以上是关于向复杂的 Django 视图添加值的主要内容,如果未能解决你的问题,请参考以下文章

Django:向视图中的请求添加可选参数

django 根据请求向所有视图添加上下文

如何根据 Django 中当前基于类的通用视图模型向模板加载器添加路径

python Django:向管理员更改列表视图添加自定义按钮

Python Django:在视图中向对象添加属性还是制作数据字典更好?

我们如何使用基于函数的视图在 django rest 框架中发布数据?