1

TL;DR: I want to save a foreign key using a CreateView class -- I can get my User groups to save, but not my own model objects.

Context: I am writing a Django-App that deals with Groups, Posts, and Users. Post entries contain a foreign key for both Group and User (a post must belong to a group and a user). I want the user to be able to add a post to a group from the group page itself -- i.e. when they access the CreateView form for this new post, there should be no 'Group' field.

My Problem: I want to save a new post object with a CreateView class with a behind-the-scenes insertion of the Group (from a slug) and User (from self.request.user). Usually, I use the form_valid() method to do this, and it works just fine for inserting the User object; however, I cannot figure out why my Group object won't save.

Some other information:

  • I know that I am able to successfully grab the Group object from the slug in the kwargs. I have assigned this object to the variable self.form_group in the get() method and I have confirmed the 'type' of the object is the correct instance of my Group class.

  • I have tried 'getting' the Group object in the form_valid() method itself: still no luck.

  • I have tried both the commented and uncommented blocks of code in the form_valid() method, respectively.

Models:

class Post(models.Model):
    user = models.ForeignKey(User, on_delete = models.CASCADE, related_name = 'posts')
    title = models.CharField(max_length = 100,default = '')
    created_at = models.DateTimeField(auto_now = True)
    post_text = models.TextField()
    post_text_html = models.TextField(editable = False) 
    group = models.ForeignKey(Group, on_delete = models.CASCADE, related_name = 'posts', null = True, blank = True)

-

class Group(models.Model):
     name = models.CharField(max_length = 255, unique = True)
     slug = models.SlugField(allow_unicode = True, unique = True)
     description = models.CharField(max_length = 5000, blank = True, default = '')
     description_html = models.TextField(editable = False, blank = True, default = '')  # Cannot be Edited
     members = models.ManyToManyField(User, through = 'GroupMember')

Views.py

 class CreatePostInGroup(LoginRequiredMixin, SelectRelatedMixin, generic.CreateView):
    model = Post
    fields = ['title', 'post_text']
    template_name = 'posts/post_in_group_form.html'

    def get(self, request, *args, **kwargs):
        print(self.kwargs)
        print(type(self.request.user))
        self.form_group = get_object_or_404(Group, slug=self.kwargs.get('slug'))
        print(type(self.form_group))
        return super(CreatePostInGroup, self).get(request, *args, **kwargs)

    def form_valid(self, form):
        form.instance.user = self.request.user
        try:
            form.instance.group = self.form_group
        except:
            return Http404
        return super(CreatPostInGroup, self).form_valid(form)

    def get_context_data(self, *args, **kwargs):
        context = super(CreatePostInGroup, self).get_context_data(*args, **kwargs)
        context['group'] = Group.objects.get(slug=self.kwargs.get('slug'))
        return context

Thank you for any help, this has been driving me nuts!

2 Answers2

0

I think your error is trying to call the super method. Essentially, if you look into what form_valid does:

def form_valid(self, form):
    """If the form is valid, save the associated model."""
    self.object = form.save()
    return super().form_valid(form)

So in other words, after you save your post with the group and user added in, the form then saves again without that, overwriting your first save. Here's what I'd recommend:

self.object = form.save(commit = False)
self.object.group = self.form_group
self.object.user = self.request.user
self.object.save()

And then use return redirect() to redirect to wherever you need to go

  • According to a similar question on StackOverflow (https://stackoverflow.com/questions/10382838/how-to-set-foreignkey-in-createview), the super call is needed. Also, my User object always successfully saves, just not the Group object. – Alijah O'Connor May 25 '18 at 11:36
  • The super call does two things. First it saves the form (this is the issue, and why you need to take it out. Essentially it is overriding your previous save procedures). The other, important thing it does is it returns an HTTP redirect to the success URL of the view. You are going to need to replace this as well: as I mentioned in the previous answer, you are going to need to use something like: return redirect(self.get_success_url()). If you do not remove (and replace) the super call, your attempt to save the post with the group and user added in will be overridden, resulting in your error. – Alexander Skvortsov May 25 '18 at 11:46
  • Hmm, I've tried that now, but I still have the same issue -- the User object saves, but not the Group object. – Alijah O'Connor May 25 '18 at 17:40
  • Well, nothing in your code would make the group save. What are you trying to change in the group object? – Alexander Skvortsov May 25 '18 at 17:43
  • Oops, I meant: in the Post object that I am trying to create, the User successfully saves to it, but the Group (i.e. the one I have assigned to the variable self.form_group) doesn't. – Alijah O'Connor May 25 '18 at 18:17
  • So you're saying that the group field of the post is null after saving? Can you check that self.form_group is set right before the line that says self.object.group=self.form_group? Maybe just insert a print statement? – Alexander Skvortsov May 25 '18 at 18:21
  • No print output was being returned, which made me look into the template for the CreateView itself to see if the 'action' of the form was being sent elsewhere. Low-and-behold, I found my problem. Thanks for brainstorming with me, sir. – Alijah O'Connor May 26 '18 at 21:18
0

It turned out to be a problem not in the views or models files, but in the template. My form was sending the data to my regular 'new post' CreateView, so that's why my form_valid() method was never called and the Group was never inserted.