1

Suppose I have two models:

class Topic(models.Model):
    title = models.CharField()
    # other stuff


class Post(models.Model):
    topic = models.ForeignKey(Topic)
    body = models.TextField()
    # other stuff

And I want to create a form contains two fields: Topic.title and Post.body. Of course, I can create the following form:

class TopicForm(Form):
    title = forms.CharField()
    body = forms.TextField()
    # and so on

But I don't want to duplicate code, since I already have title and body in models. I'm looking for something like this:

class TopicForm(MagicForm):
    class Meta:
        models = (Topic, Post)
        fields = {
            Topic: ('title', ),
            Post: ('body', )
        }
    # and so on

Also, I want to use it in class based views. I mean, I would like to write view as:

class TopicCreate(CreateView):
    form_class = TopicForm

    # ...

    def form_valid(self, form):
        # some things before creating objects

As suggested in comments, I could use two forms. But I don't see any simple way to use two forms in my TopicCreate view - I should reimplement all methods belongs to getting form(at least).

So, my question is:

Is there something already implemented in Django for my requirements? Or is there a better(simpler) way?

or

Do you know a simple way with using two forms in class based view? If so, tell me, it could solve my issue too.

Community
  • 1
  • 1
awesoon
  • 32,469
  • 11
  • 74
  • 99
  • You could combine two modelforms in your view. – J. Ghyllebert Jun 26 '13 at 07:10
  • good question i never thinked such. usually create new forms. That is much better to me – suhailvs Jun 26 '13 at 07:13
  • @J.Ghyllebert, I don't see simple way to use two forms with class-based views. Looks like I should re-implement `get_form_class`, `get_form`, etc. Please, tell me, if I'm wrong and simpler way exists. Thank you, anyway, I'll try that you suggest. – awesoon Jun 26 '13 at 07:19
  • For this i would switch to a function based view, it's just way too many work getting it work in cbv's. – J. Ghyllebert Jun 26 '13 at 07:23
  • Function-based views is deprecated, isn't it? – awesoon Jun 26 '13 at 07:25
  • This may help you: [Using a mixin with a Django form class](http://stackoverflow.com/questions/7114710/using-a-mixin-with-a-django-form-class) (however you why not just use two separate forms like Sudipta suggested?) – stellarchariot Jun 26 '13 at 07:25
  • @stellarchariot, Thanks, I'll take a look on it. And, please, look at updated question - I explained why I can't(as I think) use two forms. – awesoon Jun 26 '13 at 07:35
  • @soon you should make one (1) form for this. The form should handle the _exact_ flow you want. If you have to mix two models then you should make a mixed form (one that you've created yourself). This won't violate DRY as it's is own form for a special usecase. – Henrik Andersson Jun 26 '13 at 07:38
  • @limelights, Not sure if I understood you right. You mean, I should use first form presented in my question? – awesoon Jun 26 '13 at 07:49
  • @Soon yeah it was a dumb comment and i cant change it. What I meant is that you should make 1 form for this that handles your exact use case. So yes, the first form you presented in your question. – Henrik Andersson Jun 26 '13 at 07:50
  • I don't quite understand the relationship between the form and the models. You have a 1-to-n relationship between `Topic` and `Post`, so if you used the default `ModelForm` for `Post`, you'd get a drop-down list of `Topic`s to choose from. What exactly are you expecting the `Post` form to contain? A `Topic` form on the other hand would have many related `Post`s, so which of them should it show in the form? – Aya Jun 26 '13 at 07:57
  • @Aya, I already have the `PostForm` - it contains only `body`. Now I want a `TopicForm` for creating a new `Topic` with a new `Post` - first `Post` in the `Topic`. I don't need a `Post` form, I need a `TopicForm`. Right now I will use first presented form(with copied content) - just to not lose time. Maybe later I'll try to write my own `MagicForm` to create mixed form from multiple models. – awesoon Jun 26 '13 at 08:06
  • @soon Ahh. I see. So in effect it's a single form that will create two new records. Yeah. There's nothing like that built-in to Django, although there's a similar question [here](http://stackoverflow.com/questions/569468/django-multiple-models-in-one-template-using-forms). – Aya Jun 26 '13 at 08:14

1 Answers1

2

You can create two separate forms having the required fields, for each model. Then show both forms in the template inside one html element. Both forms will get rendered and then submitted individually. You can then process the forms separately in the view.

class TopicForm(ModelForm):

    class Meta:
        model = Topic
        fields = ("title", ..)


class PostForm(ModelForm):

    class Meta:
        model = Post
        fields = ("body", ..)

In view:

form1 = TopicForm()
form2 = PostForm()

In template:

<form ...>
{{ form1 }}
{{ form2 }}
</form>

You can easily use form.save() and all other functions, without doing it all yourself.

Sudipta
  • 4,773
  • 2
  • 27
  • 42
  • That's great, but I use class-based views, and, right now, I don't see any simple way to use two forms in it(I should re-implement `get_form_class`, `get_form`, and others). Do you? If yes, tell me, please, that would be very cool. – awesoon Jun 26 '13 at 07:26
  • @soon Ohk! I haven't started using class-based views. And a quick search does not give any easy solution. A class-based view can have two forms, but only one of them can be processed at a time. A similar question can be found [here](http://stackoverflow.com/questions/6276398/multiple-form-classes-in-django-generic-class-views). Maybe, it'll be easier for you to combine the two forms into one. – Sudipta Jun 26 '13 at 09:00