Thomas Mayet
Thomas Mayet

Reputation: 1

Django duplicates my entry when I store something

When I try to save a post, the post is saved, but current user is not registered and the post is duplicated with a blank entry and the current user is not stored.

For adding the post I use not the admin app but a personal template and form.

See the problem: Screenshot

This is my view code:

from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required
from django.shortcuts import render, redirect
from .forms import NewAdminPostForm
from .models import Post, Category

# Create your views here.
def home(request):
    posts = Post.objects.all()
    categories = Category.objects.all()
    posts_last = Post.objects.order_by('-created_at')[0:3]
    return render(request, 'front/blog-list.html', {'posts': posts, 
        'categories': categories, 'posts_last': posts_last})

@login_required
def newadminpost(request):
    if request.method == 'POST':
        form = NewAdminPostForm(request.POST)
        if form.is_valid():
            post = form.save(commit=False)
            Post.objects.create(
                message=form.cleaned_data.get('message'),
                category_id=post.category_id,
                created_by=request.user
            )
            @post.save()
            return redirect('listadminpost')
    else:
        form = NewAdminPostForm()
    return render(request, 'back/new-post-blog.html', {'form': form})

@login_required
def listadminpost(request):
    posts = Post.objects.all()
    return render(request, 'back/list-post-blog.html', {'posts': posts})

Form of my Blog:

from django import forms
from .models import Post, Category


class NewAdminPostForm(forms.ModelForm):
    title = forms.CharField(label="Titre de l'article", max_length=255,)

    message = forms.CharField(widget=forms.Textarea(),
                              max_length=4000,
                              help_text="Contenu de l'article")
    pre_message = forms.CharField(label="Message de prévisu",
                                  widget=forms.Textarea(),
                                  max_length=4000,
                                  help_text="Contenu de l'article")

    class Meta:
        model = Post
        fields = ['title','meta_desc','message','pre_message','category']

Model of my Blog:

from django.db import models
from django.contrib.auth.models import User


class Category(models.Model):
    name = models.CharField(max_length=255, unique=True)
    description = models.TextField(max_length=1000)

    def __str__(self):
        return self.name

    def get_categories_count(self):
        return Category.objects.filter(post__category=self).count()


class Post(models.Model):
    title = models.CharField(max_length=255)
    meta_desc = models.TextField(max_length=320, null=True)
    pre_message = models.TextField(max_length=4000, null=True)
    message = models.TextField(max_length=4000)
    category = models.ForeignKey(Category, on_delete='cascade')
    created_at = models.DateTimeField(auto_now_add=True)
    created_by = models.ForeignKey(User, on_delete=models.CASCADE, 
                                   blank=True, null=True)

    def __str__(self):
        return self.title

Upvotes: 0

Views: 84

Answers (2)

IVNSTN
IVNSTN

Reputation: 9308

https://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.create

your code:

post.save()...Post.objects.create(

from the link above:

A convenience method for creating an object and saving it all in one step. Thus:

p = Person.objects.create(first_name="Bruce", last_name="Springsteen")

and:

p = Person(first_name="Bruce", last_name="Springsteen")

p.save(force_insert=True)

are equivalent.

So what you do in your code:

  • you save post object created from form
  • you create and save another Post instance by calling create method

choose any of them, just one, and this will avoid duplicates.

Upvotes: 2

Olivier Pons
Olivier Pons

Reputation: 15796

Instead of doing this:

@login_required
def newadminpost(request):
    if request.method == 'POST':
        form = NewAdminPostForm(request.POST)
        if form.is_valid():
            post = form.save(commit=False)
            Post.objects.create(
                message=form.cleaned_data.get('message'),
                category_id=post.category_id,
                created_by=request.user
            )
            @post.save()
            return redirect('listadminpost')
    else:
        form = NewAdminPostForm()
    return render(request, 'back/new-post-blog.html', {'form': form})

You could do this: cleaner, easier to read, more up-to-date, and easier to maintain:

class AdminCreateView(LoginRequiredMixin, generic.CreateView):
    model = Request
    form_class = RequestForm

    def form_valid(self, form):
        result = super(AdminCreateView, self).form_valid(form)
        title = form.cleaned_data.get('title')
        meta_desc = form.cleaned_data.get('meta_desc')
        message = form.cleaned_data.get('message')

        # and so on. if there's something you refuse (ex title empty) do this:
        if not title:
            form.add_error('title', _("Precise the title"))
            return self.form_invalid(form)
        Post.objects.create(message=message,
                            meta_desc=meta_desc,
                            title=title,)  # and so on
        return result

Upvotes: 0

Related Questions