如何使用Django中的基于类的视图将父对象作为fk传递给子对象的ModelForm? [英] How do I pass a parent id as an fk to child object's ModelForm using generic class-based views in Django?

查看:315
本文介绍了如何使用Django中的基于类的视图将父对象作为fk传递给子对象的ModelForm?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Django Generic Class-Based Views来构建一个两模型数据库的CRUD接口。我有一个工作的CRUD接口到父模型,并且卡住了试图让小孩创建工作。为了与其他Django示例保持一致,请将父级作为作者,孩子作为Book。允许用户向作者添加图书的最简单的方法是什么?



在HTML术语中,我想我想在作者详细信息页面上创建一个链接,其中包含作者的ID,将该ID设置在预订表格,然后让书表处理使用该ID作为本书的PK。但是我不明白如何使用Django来实现这一点。我已阅读 https://docs.djangoproject .com / en / 1.6 / topics / class-based-views / generic-editing / 如何使用CreateView与ModelForm 如何在基于Django类的通用createview中设置请求数据的初始数据,而在基于类的通用视图中将初始值设置为modelform ,其中每一个似乎都回答了一个稍微不同的问题。



以下是相关代码:



models.py

 类作者(models.Model):
name = models.CharField(max_length = 100)

class book(models.Model):
author = models.ForeignKey(作者)
title = models.CharField(max_length = 500)

views.py

  class BookCreate CreateView):
form_class = BookForm

def get_success_url(self):
return reverse('myapp:author_read',args =(self.object.author.pk))

forms.py




class = Book
$ / code code code code code $ p>

urls.py

  url '^(?P< pk> \d +)/ $',AuthorRead.as_view(),name ='author_read'),
url(r'^ book / create /(?P< author_id& d +)/ $',Bo okCreate.as_view(),name ='book_create'),

templates / myapp / author_detail .html

  ... 
< p>< a href ={%url 'myapp:book_create'author_id = Author.pk%}>添加一本书< / a>< / p>
...

templates / myapp / book_form.html

 < form action =method =post> 
{%csrf_token%}
{{form.as_p}}
< input type =submitvalue =Done>
< / form>

问题



1)如何将作者ID从Book页面URL中获取到作者表单,然后正确处理?使用上面的示例代码,Django调试器显示它以这种方式存在:

 查看功能参数关键字参数URL名称
myapp.views.BookCreate(){'author_id':u'1234'} book_create

我不明白如何从...上下文中获取该变量...并将其放入表单中。



1a)我可以将其设置为url参数,而不是URL本身的一部分,即 book / create?author = 1234 而不是 book / create / 1234 / ?或者甚至使整个事情成为一个POST,这不是URL的一部分?这是最好的做法,它是如何完成的?



2)一旦变量以形式出现,它如何作为隐藏的输入存在,用户不必看到它?

解决方案

使用您在 author_detail.html中定义的url author_id变量将在视图中以 self.kwargs ['author_id']

 #views.py 
class BookCreate(CreateView):
...
def form_valid(self,form):
book = form.save(commit = False)
author_id = form.data ['author_id']
author = get_object_or_404(作者,id = author_id)
book.author = author
返回超级(BookCreate,self).form_valid(form)
...
def get_context_data(self,** kwargs):
context = super(BookCreate,self).get_context_data(** kwargs)
上下文['a_id'] = self.kwargs ['author_id']
返回上下文

然后在y我们的表单可以添加:

  class BookForm(forms.Modelform):
...
def __init __(self,* args,** kwargs):
self.fields [author_id] = forms.CharField(widget = forms.HiddenInput())
super(BookForm,self).__ init __ self,* args,** kwargs)

然后在模板中:

 < input type = hidden name =author_idvalue ={{a_id}}> 

视图中的form_valid应该检索该id,获取相应的作者并将该作者设置为书作者。 commit = False 防止在设置作者时首先得到保存的模型,并调用super将导致 form.save(commit = True)被调用。


I am trying to use Django Generic Class-Based Views to build a CRUD interface to a two-model database. I have a working CRUD interface to the parent model, and am stuck trying to get the child Create working. For consistency with other Django examples, take the parent to be Author and the child to be Book. What is the simplest way to allow users to add Books to an Author?

In HTML terms, I think that I want to make a link on the Author detail page that includes the ID of the Author, have that ID be pre-set on the Book form, and then have the Book form processing use that ID as the PK of the Book. But I don't understand how to use Django to make this happen. I have read through https://docs.djangoproject.com/en/1.6/topics/class-based-views/generic-editing/, How do I use CreateView with a ModelForm, How do I set initial data on a Django class based generic createview with request data, and Set initial value to modelform in class based generic views, each of which seems to answer a slightly different question.

Here is the relevant code:

models.py

class Author(models.Model):
    name = models.CharField(max_length=100)

class Book(models.Model):
    author = models.ForeignKey(Author)
    title = models.CharField(max_length=500)

views.py

class BookCreate(CreateView):
    form_class = BookForm

    def get_success_url(self):
        return reverse('myapp:author_read',args=(self.object.author.pk))

forms.py

class BookForm(forms.Modelform):
    class Meta:
        model = Book

urls.py

url(r'^(?P<pk>\d+)/$', AuthorRead.as_view(), name='author_read'),
url(r'^book/create/(?P<author_id>\d+)/$', BookCreate.as_view(), name='book_create'),

templates/myapp/author_detail.html

...
<p><a href="{% url 'myapp:book_create' author_id=Author.pk %}">Add a book</a></p>
...

templates/myapp/book_form.html

<form action="" method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <input type="submit" value="Done">
</form>

Questions

1) How do I get the Author ID from the Book page URL to the Author form, and then processed correctly? With the sample code above, the Django debugger shows that it's present in this way:

View function            Arguments      Keyword arguments         URL name
myapp.views.BookCreate   ()             {'author_id': u'1234'}    book_create

but I don't understand how to grab that variable out of the ... context? ... and put it into the form.

1a) Can I make it a url parameter instead of part of the URL itself, i.e., book/create?author=1234 instead of book/create/1234/? Or even make the whole thing a POST so that it's not part of the URL? Which is the best practice, and how is it done?

2) Once the variable is in the form, how can it be present as a hidden input, so that the user doesn't have to see it?

解决方案

With the url that you defined in author_detail.html the author_id variable will be accessible in the view as self.kwargs['author_id']

# views.py
class BookCreate(CreateView):
...
def form_valid(self, form):
    book = form.save(commit=False)
    author_id = form.data['author_id']
    author = get_object_or_404(Author, id=author_id)
    book.author = author
    return super(BookCreate, self).form_valid(form)
...
def get_context_data(self, **kwargs):
    context = super(BookCreate, self).get_context_data(**kwargs)
    context['a_id'] = self.kwargs['author_id']
    return context

Then in your form you can add:

class BookForm(forms.Modelform):
    ...
    def __init__(self, *args, **kwargs):
        self.fields["author_id"] = forms.CharField(widget=forms.HiddenInput())
        super(BookForm, self).__init__(self, *args, **kwargs)

Then in the template:

  <input type=hidden name="author_id" value="{{ a_id }}">

The form_valid in the view should retrieve the id, get the appropriate author and set that author as the books author. The commit=False prevents the model getting saved at first while you set the author and calling super will result in form.save(commit=True) being called.

这篇关于如何使用Django中的基于类的视图将父对象作为fk传递给子对象的ModelForm?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆