使用基于类的视图(UpdateView),只需一个按钮“提交”即可更新同一模板中的两个不同模型

时间:2018-12-24 00:03:48

标签: django python-3.x

我想用一个按钮更新两个不同的模型。使用基于类的视图(UpdateView)。 例如...

class AboutMe(models.Model):
    adress = models.CharField(max_length=13, null=True)
    phone_number = models.CharField(max_length=13, null=True)
class MoreAboutMe(models.Model):
    MySecondAdress = models.CharField(max_length=100)

1 个答案:

答案 0 :(得分:2)

有趣的问题,答案可能会有点长。但是它应该主要回答您的问题。

首先,我对您的模型架构进行了一些修改,以便在我们更新记录时保持整洁。基本上,我已经向foreignkey模型中添加了MoreAboutMe

models.py

from django.db import models

class AboutMe(models.Model):
    adress = models.CharField(max_length=13, null=True)
    phone_number = models.CharField(max_length=13, null=True)


class MoreAboutMe(models.Model):
    adress = models.ForeignKey(
        AboutMe,
        null=True,
        blank=True,
        on_delete=models.DO_NOTHING,
        related_name='more'
    )
    MySecondAdress = models.CharField(max_length=100)

然后,我创建了一个可以处理两个模型字段的自定义Form

forms.py

from django import forms
from MY_APP import models


class CustomForm(forms.ModelForm):

    adress = forms.CharField(max_length=200, required=True)
    phone_number = forms.CharField(max_length=200, required=True)
    second_adress = forms.CharField(max_length=200, required=True)

    class Meta:
        model = models.AboutMe
        fields = '__all__'

然后,视图:

views.py

from django.views.generic import CreateView, UpdateView
from django.urls import reverse_lazy
from django.contrib import messages
from MY_APP import models, forms


class MeView(UpdateView):
    # Here we'll use AboutMe as a base model that
    # UpdateView will handle automatically
    model = models.AboutMe
    template_name = 'about_me.html'
    # Add our custom form
    form_class = forms.CustomForm 
    # Here we add empty initials and we'll populate them later
    initial = {}

    def get_initial(self):
        """
        Add the initials of the AboutMe form
        Add the initial value of second_adress field of the form
        """
        base_initial = super().get_initial()
        # The bad part of this example
        # is i used the user's pk for thr DB queries
        # It's not safe in this case
        # this is why you need to update your model's architecutre
        base_initial['second_adress'] = models.MoreAboutMe.objects.get(
            adress__pk=self.request.user.pk
        ).MySecondAdress
        return base_initial

    def get_success_url(self):
        """Add success URL
           Here we used the user's pk value for the URL reverse
        """
        return reverse_lazy('about_me', kwargs={'pk': self.request.user.pk})

    def get_context_data(self, **kwargs):
        """
        Add MoreAboutMe model to the context data
        if you want to acess to MoreAboutMe model's records
        in the about_me.html template and in the view's methods
        """
        context = super().get_context_data(**kwargs)
        context['second_model'] = models.MoreAboutMe.objects.get(
            adress__pk=self.request.user.pk
        )
        return context

    def form_valid(self, form):
        """
        Here the tricky part: We get the cleaned data from the form then
        we'll update manually the MySecondAdress field then let Django handles 
        the rest of fields using the UpdateView Mixin
        """
        second_adress = form.cleaned_data.get('second_adress', None)
        if second_adress:
            instance = self.get_context_data().get('second_model')
            instance.MySecondAdress = second_adress
            instance.save()
        return super().form_valid(form)

    def post(self, *args, **kwargs):
        """Add a sucess message using the django's message framework"""
        messages.success(self.request, 'Updated')
        return super().post(*args, **kwargs)

然后:

urls.py

from django.urls import path
from MY_APP import views


urlpatterns = [
    path('about-me/<int:pk>/', views.MeView.as_view(), name='about_me')
]

最后:

about_me.html

{% for message in messages %}
    {{ message }}
{% endfor %}
<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <input type="submit" value="Submit">
</form>

奖金:这是一个演示

提交之前:

Before the Submit

提交后:

After the Submit

注意:您需要更新模型架构,以保持记录整洁,并记住您的应用程序将来需要扩展。