• Django如何实现多对一数据的添加


    例如:新增一个文章时,需要"新增另一个"的按钮
    关键词:django、inlineform、form

    目标效果:

    image

    参考链接:

    具体实现

    • 安装两个第三方的包:

      pip install django-crispy-forms django-dynamic-formsets
      
    • models.py

      class Articles(models.Model):
          user = models.ForeignKey(Client,on_delete=models.CASCADE,verbose_name="所属用户")
          content = models.CharField(max_length=200,verbose_name="正文")
          create_time = models.DateTimeField(auto_now_add=True,verbose_name="创建时间")
          last_edit_time = models.DateTimeField(auto_now=True,verbose_name="最后一次编辑时间")
          is_public = models.CharField(max_length=5,choices=(("T","发布"),("F","仅自己可见")),verbose_name="是否发布")
          view = models.PositiveSmallIntegerField(default=0,verbose_name="阅读数")
          like = models.PositiveSmallIntegerField(default=0,verbose_name="点赞数")
      
          class Meta:
              verbose_name = "文章"
              verbose_name_plural = verbose_name
              ordering = ["-create_time"]
      
      
      
      class Images(models.Model):
          img = models.FileField(upload_to="articles_img",verbose_name="图片")
          articles = models.ForeignKey(Articles,on_delete=models.CASCADE,verbose_name="所属文章")
          create_time = models.DateTimeField(auto_now_add=True,verbose_name="上传时间")
      
          class Meta:
              verbose_name = "文章图片"
              verbose_name_plural = verbose_name
              ordering = ["-create_time"]
      
    • urls.py

      from django.urls import path
      from main_app import views
      
      app_name = 'main_app'
      
      urlpatterns = [
          path('create_articles/',views.ArticlesCreate.as_view(),name="create_articles"),
          ...
      ]
      
    • views.py

      from main_app import models
      from main_app import forms
      
      class ArticlesCreate(LoginRequiredMixin,CreateView):
          model = models.Articles
          template_name = "articles_add.html"
          form_class = forms.ArticlesForm
          success_url = None
      
          def get_context_data(self, **kwargs):
              data = super(ArticlesCreate, self).get_context_data(**kwargs)
              if self.request.POST:
                  data['images_formset'] = accounts_forms.ImagesFormSet(self.request.POST,self.request.FILES)
              else:
                  data['images_formset'] = accounts_forms.ImagesFormSet()
              return data
      
          def form_valid(self, form):
              context = self.get_context_data()
              images_formset = context['images_formset']
              with transaction.atomic():
                  form.instance.user = self.request.user.client
                  self.object = form.save()
                  if images_formset.is_valid():
                      images_formset.instance = self.object
                      images_formset.save()
              return super(ArticlesCreate, self).form_valid(form)
      
          def get_success_url(self):
              return reverse_lazy('main_app:index')
      
      
    • forms.py

      from django import forms
      from django.forms.models import inlineformset_factory
      
      from crispy_forms.helper import FormHelper
      from crispy_forms.layout import Layout, Field, Fieldset, Div, HTML, ButtonHolder, Submit
      
      from main_app import models
      from main_app.custom_layout_object import Formset
      
      class ImagesForms(forms.ModelForm):
          class Meta:
              model = models.Images
              fields = ("img",)
      
      ImagesFormSet = inlineformset_factory(
          models.Articles,
          models.Images,
          form=ImagesForms,
          extra=1,
          can_delete=True
      )
      
      class ArticlesForm(forms.ModelForm):
          content = CustomCharField(label="正文",widget=forms.Textarea(attrs={"rows":3}))
          class Meta:
              model = models.Articles
              fields = ("content","is_public")
      
          def __init__(self, *args, **kwargs):
              super(ArticlesForm, self).__init__(*args, **kwargs)
              self.helper = FormHelper()
              self.helper.form_tag = True
              self.helper.form_class = ''
              self.helper.layout = Layout(
                  Div(
                      Field('content'),
                      Field('is_public'),
                      Fieldset('添加图片',
                               Formset('titles')),
                      ButtonHolder(Submit('submit', '保存')),
                  )
              )
      
      
    • main_app/custom_layout_object.py

      from crispy_forms.layout import LayoutObject, TEMPLATE_PACK
      from django.shortcuts import render
      from django.template.loader import render_to_string
      
      
      class Formset(LayoutObject):
          template = "formset.html"
      
          def __init__(self, formset_name_in_context, template=None):
              self.formset_name_in_context = formset_name_in_context
              self.fields = []
              if template:
                  self.template = template
      
      
          def render(self, form, form_style, context, template_pack=TEMPLATE_PACK):
              formset = context[self.formset_name_in_context]
              return render_to_string(self.template, {'formset': formset})
      
    • formset.html

      这里我新增了一些js代码用于隐藏不需要的按钮

      {% load crispy_forms_tags %}
      {% load static %}
      {% load crispy_forms_tags %}
      <table class="col-md-9" style="margin-left: 10px;">
      {{ formset.management_form|crispy }}
          {% for form in formset.forms %}
              <tr class="{% cycle 'row1' 'row2' %} formset_row-{{ formset.prefix }}">
                  {% for field in form.visible_fields %}
                  <td>
                      {# Include the hidden fields in the form #}
                      {% if forloop.first %}
                          {% for hidden in form.hidden_fields %}
                              {{ hidden }}
                          {% endfor %}
                      {% endif %}
                      {{ field.errors.as_ul }}
                      {{ field|as_crispy_field }}
                  </td>
                  {% endfor %}
              </tr>
          {% endfor %}
      
      </table>
      <br>
      <script src="{% static 'bootstrap/jquery-3.6.0.min.js' %}"></script>
      <script src='{% static "dynamic_formsets/jquery.formset.js" %}'></script>
      <script type="text/javascript">
          $('.formset_row-{{ formset.prefix }}').formset({
              addText: '<i class="bi bi-plus"></i>新增另一个',
              deleteText: '<i class="bi bi-trash"></i>删除',
              prefix: '{{ formset.prefix }}',
          });
          $("input[type='checkbox']").each(hiddenLabel)
          function hiddenLabel(index,element){
              console.log(element)
              $(element).attr("hidden",true)
              $($(element)[0].labels[0]).attr("hidden",true)
          }
      
      </script>
      
    • articles_add.html

      {% extends "base.html" %}
      {% load crispy_forms_tags %}
      {% block title %}编辑文章{% endblock %}
      {% block css %}
          <style>
              .asteriskField{
                  color: red;
              }
              .col-md-9 label{
                  color: grey !important;
              }
              .delete-row{
                  color: red !important;
                  font-size: 1rem !important;
              }
          </style>
      {% endblock %}
      {% block content %}
      <div class="container">
          <div class="card">
              <div class="card-header">
                  编辑文章
              </div>
              <div class="card-body">
                   {% crispy form %}
              </div>
          </div>
      </div>
      {% endblock content %}
      {% block js %}
          <script>
              $("form").attr("enctype","multipart/form-data")
          </script>
      {% endblock %}
      
  • 相关阅读:
    RabbitMQ一:消息队列的认识
    RabbitMQ二:AMQP协议
    SVN中如何去除版本控制器
    Asp.net:MVC认识
    时间连接查询展示
    C#string类型总结
    JavaScript01天学习笔记分享
    UML中的类图及类图之间的关系
    23 种设计模式的分类和功能
    WCF入门
  • 原文地址:https://www.cnblogs.com/lisicn/p/15792227.html
Copyright © 2020-2023  润新知