MerrinX
MerrinX

Reputation: 183

Django create post

I am trying to create a new post to a forum, and it does work, i am also printing if the form is valid, but when i go to check after the post is not posted. In the admin page, the post is there, approved, but missing the tags and category fields. They was added when the post was created, if not i get an error. But I have to manually add them in the admin page to get the post posted to the forum.

Here is my Post in models

class Post(models.Model):
    title = models.CharField(max_length=400)
    slug = models.SlugField(max_length=400, unique=True, blank=True)
    user = models.ForeignKey(Author, on_delete=models.CASCADE)
    content = HTMLField()
    categories = models.ManyToManyField(Category)
    date = models.DateTimeField(auto_now_add=True)
    approved = models.BooleanField(default=True)
    tags = TaggableManager()
    comments = models.ManyToManyField(Comment, blank=True)
    # closed = models.BooleanField(default=False)
    # state = models.CharField(max_length=40, default="zero")

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.title)
        super(Post, self).save(*args, **kwargs)

    def __str__(self):
        return self.title

Here is my views.py

@login_required
def create_post(request):
    context = {}
    form = PostForm(request.POST or None)
    if request.method == "POST":
        if form.is_valid():
            print("\n\n form is valid")
            author = Author.objects.get(user=request.user)
            new_post = form.save(commit=False)
            new_post.user = author
            new_post.save()

            return redirect('forums')
        
    context.update({
            'form': form,
            'title': 'Create New Post'
    })
    return render(request, 'forums/create_post.html', context)

The html is just very simple, to test.

<form method="POST">
                            {% csrf_token %}    
                            {{form|crispy}}
                            <!-- Submit Post -->
                            <input type="submit" value="Save">
                        </form>

Please any help would be much appreciated

Upvotes: 3

Views: 4526

Answers (2)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477749

The reason a ModelForm can not save the many-to-many relation when commit=False is because it does not create the Post at the database side, and hence has no primary key that can be used to add the many-to-many relations.

You can use .save_m2m() to save the many to many relations after you have saved the instance wrapped in the form, but perhaps a more elegant solution is to attach the request.user to the instance wrapped in the form, and then save the form, since then the form will save the many-to-many relations as well in the same function call, so:

from django.shortcuts import get_object_or_404

# …

if form.is_valid():
    form.instance.user = get_object_or_404(Author, user=request.user)
    form.save()

It might be worth renaming the .user field to .author instead, since now it hints that it is storing a User object, not an Author object.

Upvotes: 2

raphael
raphael

Reputation: 2880

The line, new_post = form.save(commit=False) will not save the many to many relationship according to the docs. The workaround

new_post = form.save(commit=False)
new_post.user = author
new_post.save()
form.save_m2m()

Excerpt from the docs

Another side effect of using commit=False is seen when your model has a many-to-many relation with another model. If your model has a many-to-many relation and you specify commit=False when you save a form, Django cannot immediately save the form data for the many-to-many relation. This is because it isn’t possible to save many-to-many data for an instance until the instance exists in the database.

To work around this problem, every time you save a form using commit=False, Django adds a save_m2m() method to your ModelForm subclass. After you’ve manually saved the instance produced by the form, you can invoke save_m2m() to save the many-to-many form data.

I don't think this solves everything, but give it a try.

Upvotes: 4

Related Questions