Пользовательская форма Django с ManyToManyField: как добавить новый элемент из Интернета - PullRequest
0 голосов
/ 04 ноября 2019

Я добавляю специальную форму для поста в блоге с Django. У модели Post, которую я определил, есть ManytoManyField, и при попытке создать публикацию в django admin.ModelAdmin у нее есть кнопка «+», которую пользователь может добавить. Однако при создании пользовательского представления формы оно не появилось. Можно ли как-нибудь создать кнопку «+», чтобы пользователь мог создать новый элемент и добавить его, щелкнув по нему?

При добавлении модели публикации с помощью django admin.ModelAdmin у нее есть скриншоткак показано ниже (ключевые слова = ... в classPostForm были закомментированы, чтобы получить это)

Создание с помощью django admin.ModelAdmin

Однако в пользовательском представлении (включая исходный код)ниже) кнопка «+» не существует. Создание с помощью пользовательской формы

# models.py
class Post(models.Model):
    title = models.CharField(max_length=255)
    slug = models.SlugField(max_length=200, unique=True)
    keywords = models.ManyToManyField(Keyword, blank=True)
# forms.py
class PostForm(forms.ModelForm):
    keywords = forms.ModelMultipleChoiceField(
        Keyword.objects.all(),
        widget=widgets.FilteredSelectMultiple('Keywords', False),
        required=False,
    )

    def __init__(self, *args, **kwargs):
        super(PostForm, self).__init__(*args, **kwargs)

    class Meta:
        model = Post
        fields = ('title', 'keywords')

        querysets = {
            'keywords': Keyword.objects.all()
        }

    class Media:
        css = {'all': ('/admin/css/widgets.css',
                       'admin/css/overrides.css'), }
        js = ('/admin/jquery.js', '/admin/jsi18n/')
# views.py
class CreatePost(generic.CreateView):
    model = Post
    form_class = PostForm
    template_name = 'post_create.html'
<!---base.html---!>
<!DOCTYPE html>
<html>
<head>
    <title>Doc Flow</title>

    <link
            href="https://fonts.googleapis.com/css?family=Roboto:400,700"
            rel="stylesheet">
    <meta content="notranslate" name="google"/>
    <meta content="width=device-width, initial-scale=1" name="viewport"/>
    <link
            crossorigin="anonymous"
            href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
            integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
            rel="stylesheet"
    />
    <meta content="width=device-width, initial-scale=1" name="viewport">
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/js/bootstrap.min.js"></script>

    <a href="/admin/blog/post/add" class="top-menu"><span class="glyphicon glyphicon-plus"></span></a>
    {{ form.media }}
        <meta charset="utf-8">
    {% block extra_head %}
    {% endblock %}
</head>

<body>
<style>
      body {
        font-family: "Roboto", sans-serif;
        font-size: 17px;
        background-color: #fdfdfd;
      }

    .shadow{
           box-shadow: 0 4px 2px -2px rgba(0,0,0,0.1);
       }
      .btn-danger {
        color: #fff;
        background-color: #f00000;
        border-color: #dc281e;
      }

     .masthead {
              background:#3398E1;
              height: auto;
              padding-bottom: 15px;
              box-shadow: 0 16px 48px #E3E7EB;
              padding-top: 10px;
    }

    .div_slide {
        width: 30%;
        float: left;
    }
    .slide-container {
      overflow: auto;
      white-space: nowrap;
    }

</style>

<!-- Navigation -->
<nav class="navbar navbar-expand-lg navbar-light bg-light shadow" id="mainNav">
    <div class="container-fluid">
        <a class="navbar-brand" href="{% url 'home' %}">Front</a>
        <button
                aria-controls="navbarResponsive"
                aria-expanded="false"
                aria-label="Toggle navigation"
                class="navbar-toggler navbar-toggler-right"
                data-target="#navbarResponsive"
                data-toggle="collapse"
                type="button"
        >
            <span class="navbar-toggler-icon"></span>
        </button>

    </div>
    </div>
</nav>
{% block content %}
<!-- Content Goes here -->
{% endblock content %}

<!-- Footer -->
<footer class="py-3 bg-grey">
    <p class="m-0 text-dark text-center ">Copyright &copy; Workhorse</p>
</footer>

</body>
</html>
<!---post_create.html---!>
{% extends 'base.html' %}
{% block extra_head %}
  <link rel="stylesheet" type="text/css" href="/static/admin/css/base.css">
  <link rel="stylesheet" type="text/css" href="/static/admin/css/forms.css">
  <link rel="stylesheet" type="text/css" href="/static/admin/css/responsive.css">
{% endblock %}

{% block content %}
  <form method="post" autocomplete="off" novalidate>
    {% csrf_token %}
    {{ form|crispy }}
    <button type="submit" class="btn btn-success">Create event</button>
  </form>
{% endblock %}

1 Ответ

0 голосов
/ 05 ноября 2019

RelatedFieldWidgetWrapper отвечает за добавление знака "+" в ваш виджет. Так что вам нужно обернуть в него FilteredSelectMultiple, чтобы это работало.

    keywords = forms.ModelMultipleChoiceField(
        Keyword.objects.all(),
        widget=admin.widgets.RelatedFieldWidgetWrapper(
            widget=admin.widgets.FilteredSelectMultiple('Keywords', False),
            rel=Post.keywords.rel,
            admin_site=admin.site
        ),
        required=False,
    )

Это не так просто найти в документации, но мне пришлось искать в базе кода Django, чтобы добраться до нее.

...