0

The site has the ability to create a post for a specific game. When you try to create a post, it is created but the ManyToManyField remain empty. How to fix it?

forms.py

    class AddPost(forms.ModelForm):
    title = forms.CharField(label='Title', widget=forms.TextInput(attrs={'placeholder': 'Заголовок...'}),
                            help_text='Максимум 100 символів.')
    games = forms.ModelChoiceField(queryset=Game.objects.filter(draft=False), widget=forms.Select, required=True)
    tags = forms.ModelMultipleChoiceField(queryset=Tags.objects.all(), widget=forms.SelectMultiple(
        attrs={'style': "padding: 10px; background:#edf2ff; border:none;"}))
    foreword_description = forms.CharField(label='Small Description',
                                           widget=forms.Textarea(attrs={'placeholder': 'Коротке описання...'}),
                                           help_text='Максимум 335 символів.')
    description = forms.CharField(label='Description', widget=CKEditorUploadingWidget())
    rank = forms.FloatField(label='Rank', widget=forms.TextInput(attrs={'placeholder': 'Оцінка...'}))
    good = forms.ModelChoiceField(queryset=Good.objects.all(), widget=forms.Select(
        attrs={'style': "padding: 10px; background:#edf2ff; border:none;"}))
    bad = forms.ModelChoiceField(queryset=Bad.objects.all(), widget=forms.Select(
        attrs={'style': "padding: 10px; background:#edf2ff; border:none;"}))
    url = forms.SlugField(label='Title', widget=forms.TextInput(attrs={'placeholder': 'Унікальний ідентифікатор...'}),
                          help_text='Максимум 255 символів.')
    premiere = forms.DateField(label='Date', widget=forms.SelectDateWidget(attrs=({'style': 'width: 10%; display: inline-block;'})),
                               help_text='У форматі: 24.03.2022.')

    class Meta:
        model = Post
        fields = (
            'title', 'games', 'tags', "foreword_description", "description", "rank", "good", "bad", "url", "premiere",)

views.py

def addpost(request):
    if request.method == "POST":
        form = AddPost(request.POST)
        if form.is_valid():
            post = form.save(commit=False)
            post.save()

            return redirect('../blogs/')
    else:
        form = AddPost()

    data = {
        'form': form,
        'add': True
    }

    return render(request, 'gamelibs/user-post-manager.html', {'form': form})

models.py

    class Game(models.Model):
    title = models.CharField("Назва", max_length=100)
    tagline = models.CharField("Слоган", max_length=500, default='')
    description = models.TextField("Описання")
    description_small = models.CharField("Описання коротко", max_length=100, null=True)
    poster = models.ImageField("Постер", upload_to="games/poster/")
    banner = models.ImageField("Банер", upload_to="games/banner/", null=True)
    treiler = models.CharField("Трейлер", max_length=500, null=True)
    treiler_img = models.ImageField("Інтро терейлеру", upload_to="games/intro/", null=True)
    country = models.CharField("Країна", max_length=30)
    company = models.ManyToManyField(Company, verbose_name="Компанія", related_name="company_game")
    ganres = models.ManyToManyField(Ganre, verbose_name="Жанри")
    price = models.FloatField("Ціна", help_text="У форматі 10.00", max_length=100)
    sale_price = models.IntegerField('Скидка в процентах', blank=True, default=0)
    world_premiere = models.DateField("Дата виходу", default=date.today)
    budget = models.PositiveIntegerField("Бюджет", default=0, help_text="вказуйте сумму в доларах.")
    category = models.ManyToManyField(Category, verbose_name="Категорія")
    url = models.SlugField(max_length=255, unique=True)
    os = models.CharField("Операційні системи", max_length=100)
    processor = models.CharField("Процесор", max_length=100)
    memory = models.CharField("Операційна памьять", max_length=100)
    graphics = models.CharField("Відеокарта", max_length=100)
    hard_drive = models.CharField("Місце на диску", max_length=100)
    hit_count_generic = GenericRelation(HitCount, object_id_field='object_pk',
                                        related_query_name='hit_count_generic_relation', default=0)
    draft = models.BooleanField("Чернетка", default=False)

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse("game_details", kwargs={"slug": self.url})

    def get_sale(self):
        if self.sale_price == 100:
            return 'FREE'
        elif self.sale_price == 0:
            return f'{self.price}'
        else:
            price = float(self.price * (100 - self.sale_price) / 100)
            x = float('{:.2f}'.format(price))
            return x

    class Meta:
        verbose_name = "Гра"
        verbose_name_plural = "Ігри"

 

       class Tags(models.Model):
    title = models.CharField("Заголовок", max_length=100)
    url = models.SlugField(max_length=160, unique=True)

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse("tag_filter", kwargs={"slug": self.url})

    class Meta:
        verbose_name = "Тег"
        verbose_name_plural = "Теги"

    
    class Good(models.Model):
    title = models.CharField("Заголовок", max_length=100)
    url = models.SlugField(max_length=160, unique=True)

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse("good_blog_filter", kwargs={"slug": self.url})

    class Meta:
        verbose_name = "Позитив"
        verbose_name_plural = "Позитивні"


        class Bad(models.Model):
    title = models.CharField("Заголовок", max_length=100)
    url = models.SlugField(max_length=160, unique=True)

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse("bad_blog_filter", kwargs={"slug": self.url})

    class Meta:
        verbose_name = "Негатив"
        verbose_name_plural = "Негативні"
    
    class Post(models.Model):
    title = models.CharField("Заголовок", max_length=100)
    games = models.ManyToManyField(Game, verbose_name="Вкажіть гру", help_text="Вказати тільки одну гру!",
                                   related_name='games')
    tags = models.ManyToManyField(Tags, verbose_name="Теги", help_text="Вказати тільки 4 тега!")
    foreword_description = models.TextField("Передмова", max_length=335)
    description = models.TextField("Описання")
    rank = models.FloatField("Оцінка", default=0, help_text="Від 1 до 10")
    good = models.ManyToManyField(Good, verbose_name="Позитивні речі", help_text="Максимальна кількість 4")
    bad = models.ManyToManyField(Bad, verbose_name="Негативні речі", help_text="Максимальна кількість 4")
    premiere = models.DateField("Дата публікації", default=date.today)
    url = models.SlugField(max_length=255, unique=True, default="Введіть унікальний аудентифікатор")
    hit_count_generic = GenericRelation(HitCount, object_id_field='object_pk',
                                        related_query_name='hit_count_generic_relation')
    draft = models.BooleanField("Чернетка", default=False)

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse("post_details", kwargs={"slug": self.url})

    class Meta:
        verbose_name = "Пост"
        verbose_name_plural = "Пости"

html

    <form method="POST" enctype="multipart/form-data" name="filter-form">{% csrf_token %}
                    <div class="form-group">
                        <label class="control-label col-sm-2" for="cur_password">Заголовок:</label>
                        <div class="col-sm-10">
                            <div class="youplay-input">
                                {{ form.title }}
                            </div>
                            <h6><i class="fa fa-circle-exclamation"> {{ form.title.help_text }}</i></h6>
                            {{ form.title.errors }}
                        </div>
                    </div>
                    <div class="form-group">
                        <label class="control-label col-sm-2" for="new_password">Оберіть гру:</label>
                        <div class="col-sm-10">
                            <div class=" col-sm-10
                              field-games">
                                <div class="related-widget-wrapper">
                                    {{ form.games }}
                                    {{ form.games.errors }}
                                </div>
                            </div>
                        </div>
                    </div>
                    <div class="form-group">
                        <label class="control-label col-sm-2" for="new_password">Оберіть теги:</label>
                        <div class="col-sm-10">
                            {{ form.tags }}
                            {{ form.tags.errors }}
                        </div>
                    </div>
                    <div class="form-group">
                        <label class="control-label col-sm-2" for="cur_password">Коротке описання:</label>
                        <div class="col-sm-10">
                            <div class="youplay-input">
                                {{ form.foreword_description }}
                            </div>
                            <h6><i class="fa fa-circle-exclamation"> {{ form.foreword_description.help_text }}</i></h6>
                            {{ form.foreword_description.errors }}
                        </div>
                    </div>
                    <div class="form-group">
                        <label class="control-label col-sm-2" for="cur_password">Описання:</label>
                        <div class="col-sm-10">
                            {{ form.description }}
                            {{ form.description.errors }}
                        </div>
                    </div>
                    <div class="form-group">
                        <label class="control-label col-sm-2" for="cur_password">Оцінка гри:</label>
                        <div class="col-sm-10">
                            <div class="youplay-input">
                                {{ form.rank }}
                            </div>
                            {{ form.rank.errors }}
                        </div>
                    </div>
                    <div class="form-group">
                        <label class="control-label col-sm-2" for="new_password">Позитивні речі:</label>
                        <div class="col-sm-10">
                            {{ form.good }}
                            {{ form.good.errors }}
                        </div>
                    </div>
                    <div class="form-group">
                        <label class="control-label col-sm-2" for="new_password">Негативні речі:</label>
                        <div class="col-sm-10">
                            {{ form.bad }}
                            {{ form.bad.errors }}
                        </div>
                    </div>
                    <div class="form-group">
                        <label class="control-label col-sm-2" for="cur_password">URL:</label>
                        <div class="col-sm-10">
                            <div class="youplay-input">
                                {{ form.url }}
                            </div>
                            <h6><i class="fa fa-circle-exclamation"> {{ form.url.help_text }}</i></h6>
                            {{ form.url.errors }}
                        </div>
                    </div>
                    <div class="form-group">
                        <label class="control-label col-sm-2" for="cur_password">Дата:</label>
                        <div class="col-sm-10">

                            {{ form.premiere }}

                            <h6><i class="fa fa-circle-exclamation"> {{ form.premiere.help_text }}</i></h6>
                            {{ form.premiere.errors }}
                        </div>
                    </div>
                    <div class="form-group">
                        <div class="col-sm-offset-2 col-sm-10">
                            <button type="submit" class="btn btn-default">Створити Пост</button>
                        </div>
                    </div>
                </form>

What am I doing wrong or how else can I implement this? I just don't fully understand why the form is saved, but the ModelChoiceField fields are empty, why? I will be grateful for your answers

Lukash
  • 11
  • 1

1 Answers1

0

There is a disconnect between your many-to-many fields and your form.

Let's take 'game'. In your model it's a many-to-many field. But in your form it's a ModelChoiceField. A ModelChoiceField should link to a field that has a Foreignkey relationship (many to one), not a many to many. So, in this case, your model is saying a post can be about many different games, but your form only allowing the user to select one. With a one to many, you can still have many posts (plural) referring to the same game, but each individual post can only refer to one.

If you want the user to be able to select multiple games for each post, then the form should have a ModelMultipleChoiceField. If you only want a post to be about one game, then the model should have a ForiegnKey (one-to-many) rather than a many-to-many relationship. Then the form and the model will align and handle each other appropriately.

SamSparx
  • 4,629
  • 1
  • 4
  • 16