Django 将父对象传递到子对象的CreateView

Django 将父对象传递到子对象的CreateView,django,django-models,django-forms,django-views,django-templates,Django,Django Models,Django Forms,Django Views,Django Templates,我正在创建一个仪表板来编辑旅游应用程序 每次巡演我都有一个子记录,我在其中定义了步骤。这两种型号如下所示: 型号.py class Tour(models.Model): tour_id = models.CharField(primary_key=True,unique=True, max_length=10) country = models.ForeignKey(Countries, models.DO_NOTHING, db_column='country') l

我正在创建一个仪表板来编辑旅游应用程序

每次巡演我都有一个子记录,我在其中定义了步骤。这两种型号如下所示:

型号.py

class Tour(models.Model):
    tour_id = models.CharField(primary_key=True,unique=True, max_length=10)
    country = models.ForeignKey(Countries, models.DO_NOTHING, db_column='country')
    language = models.ForeignKey(Language, models.DO_NOTHING, db_column='language')
    lastupddtm = models.DateTimeField(default=timezone.now)
    productid = models.CharField(max_length=50)
    title = models.CharField(max_length=50)
    description = models.CharField(max_length=100)
    descrlong = models.CharField(max_length=1000)
    live = models.CharField(max_length=1)
    image = models.ImageField(upload_to=upload_tour_image, storage=OverwriteStorage(), blank=True, null=True)

    class Meta:
        db_table = 'tour'
        verbose_name_plural = "tour"


    def get_language_flag(self):
        return self.language.flag.url

    def __str__(self):
        return str(self.tour_id) + ' - ' + str(self.title) + ' - ' + str(self.description)



class Toursteps(models.Model):
    # tour_id = models.OneToOneField(Tour, models.DO_NOTHING, db_column='tour_id')
    tour = models.ForeignKey(Tour, related_name='toursteps', on_delete=models.CASCADE)
    step = models.IntegerField(unique=True)
    title = models.CharField(max_length=50)
    description = models.CharField(max_length=100)
    descrlong = models.CharField(max_length=1000)
    audiotext = models.TextField()
    latitude = models.FloatField()
    longitude = models.FloatField()
    radius = models.FloatField()
    image = models.ImageField(upload_to=upload_tour_step_image, blank=True, null=True)

    class Meta:
        db_table = 'tourSteps'
        verbose_name_plural = "tourSteps"

    def __str__(self):
        return str(self.tour) + "|" + str(self.step)
urlpatterns = [
    path('tour/<str:pk>/detail', views.TourDetailView.as_view(), name='tour_detail'),
    path('tour/<str:pk>/edit', views.UpdateTourView.as_view(), name='tour_edit'),
    path('tour/<str:pk>/remove', views.DeleteTourView.as_view(), name='tour_remove'),
    path('tour/<str:tour_id>/step/new', views.CreateTourStepView.as_view(), name='tour_step_new')
]
class CreateTourStepView(LoginRequiredMixin,CreateView):
    login_url = '/login/'
    redirect_field_name = 'tour_admin/tour_list.html'
    success_url = '/'
    form_class = TourStepForm
    model = Toursteps

    def get_context_data(self, **kwargs):
        context = super(CreateTourStepView, self).get_context_data(**kwargs)
        print(context['tour_id'])
        return context
class TourStepForm(forms.ModelForm):

    class Meta():
        model = Toursteps
        #fields = '__all__'
        exclude = ('tour',)

    def form_valid(self, form):
        if form.is_valid():
            form.instance.tour_id = self.request.GET("tour_id")

            form.instance.save()

            return HttpResponseRedirect(self.get_success_url())

    def get_success_url(self):
        return reverse('tour_detail', kwargs={'pk':form.instance.tour_id})
创建巡更后,我转到详细信息页面。从那里,我可以单击一个链接来添加此教程的步骤。 这就是问题所在。我将tour_id作为变量传递到url中,但在步骤的CreateView中找不到获取它的方法

url.py

class Tour(models.Model):
    tour_id = models.CharField(primary_key=True,unique=True, max_length=10)
    country = models.ForeignKey(Countries, models.DO_NOTHING, db_column='country')
    language = models.ForeignKey(Language, models.DO_NOTHING, db_column='language')
    lastupddtm = models.DateTimeField(default=timezone.now)
    productid = models.CharField(max_length=50)
    title = models.CharField(max_length=50)
    description = models.CharField(max_length=100)
    descrlong = models.CharField(max_length=1000)
    live = models.CharField(max_length=1)
    image = models.ImageField(upload_to=upload_tour_image, storage=OverwriteStorage(), blank=True, null=True)

    class Meta:
        db_table = 'tour'
        verbose_name_plural = "tour"


    def get_language_flag(self):
        return self.language.flag.url

    def __str__(self):
        return str(self.tour_id) + ' - ' + str(self.title) + ' - ' + str(self.description)



class Toursteps(models.Model):
    # tour_id = models.OneToOneField(Tour, models.DO_NOTHING, db_column='tour_id')
    tour = models.ForeignKey(Tour, related_name='toursteps', on_delete=models.CASCADE)
    step = models.IntegerField(unique=True)
    title = models.CharField(max_length=50)
    description = models.CharField(max_length=100)
    descrlong = models.CharField(max_length=1000)
    audiotext = models.TextField()
    latitude = models.FloatField()
    longitude = models.FloatField()
    radius = models.FloatField()
    image = models.ImageField(upload_to=upload_tour_step_image, blank=True, null=True)

    class Meta:
        db_table = 'tourSteps'
        verbose_name_plural = "tourSteps"

    def __str__(self):
        return str(self.tour) + "|" + str(self.step)
urlpatterns = [
    path('tour/<str:pk>/detail', views.TourDetailView.as_view(), name='tour_detail'),
    path('tour/<str:pk>/edit', views.UpdateTourView.as_view(), name='tour_edit'),
    path('tour/<str:pk>/remove', views.DeleteTourView.as_view(), name='tour_remove'),
    path('tour/<str:tour_id>/step/new', views.CreateTourStepView.as_view(), name='tour_step_new')
]
class CreateTourStepView(LoginRequiredMixin,CreateView):
    login_url = '/login/'
    redirect_field_name = 'tour_admin/tour_list.html'
    success_url = '/'
    form_class = TourStepForm
    model = Toursteps

    def get_context_data(self, **kwargs):
        context = super(CreateTourStepView, self).get_context_data(**kwargs)
        print(context['tour_id'])
        return context
class TourStepForm(forms.ModelForm):

    class Meta():
        model = Toursteps
        #fields = '__all__'
        exclude = ('tour',)

    def form_valid(self, form):
        if form.is_valid():
            form.instance.tour_id = self.request.GET("tour_id")

            form.instance.save()

            return HttpResponseRedirect(self.get_success_url())

    def get_success_url(self):
        return reverse('tour_detail', kwargs={'pk':form.instance.tour_id})
forms.py

class Tour(models.Model):
    tour_id = models.CharField(primary_key=True,unique=True, max_length=10)
    country = models.ForeignKey(Countries, models.DO_NOTHING, db_column='country')
    language = models.ForeignKey(Language, models.DO_NOTHING, db_column='language')
    lastupddtm = models.DateTimeField(default=timezone.now)
    productid = models.CharField(max_length=50)
    title = models.CharField(max_length=50)
    description = models.CharField(max_length=100)
    descrlong = models.CharField(max_length=1000)
    live = models.CharField(max_length=1)
    image = models.ImageField(upload_to=upload_tour_image, storage=OverwriteStorage(), blank=True, null=True)

    class Meta:
        db_table = 'tour'
        verbose_name_plural = "tour"


    def get_language_flag(self):
        return self.language.flag.url

    def __str__(self):
        return str(self.tour_id) + ' - ' + str(self.title) + ' - ' + str(self.description)



class Toursteps(models.Model):
    # tour_id = models.OneToOneField(Tour, models.DO_NOTHING, db_column='tour_id')
    tour = models.ForeignKey(Tour, related_name='toursteps', on_delete=models.CASCADE)
    step = models.IntegerField(unique=True)
    title = models.CharField(max_length=50)
    description = models.CharField(max_length=100)
    descrlong = models.CharField(max_length=1000)
    audiotext = models.TextField()
    latitude = models.FloatField()
    longitude = models.FloatField()
    radius = models.FloatField()
    image = models.ImageField(upload_to=upload_tour_step_image, blank=True, null=True)

    class Meta:
        db_table = 'tourSteps'
        verbose_name_plural = "tourSteps"

    def __str__(self):
        return str(self.tour) + "|" + str(self.step)
urlpatterns = [
    path('tour/<str:pk>/detail', views.TourDetailView.as_view(), name='tour_detail'),
    path('tour/<str:pk>/edit', views.UpdateTourView.as_view(), name='tour_edit'),
    path('tour/<str:pk>/remove', views.DeleteTourView.as_view(), name='tour_remove'),
    path('tour/<str:tour_id>/step/new', views.CreateTourStepView.as_view(), name='tour_step_new')
]
class CreateTourStepView(LoginRequiredMixin,CreateView):
    login_url = '/login/'
    redirect_field_name = 'tour_admin/tour_list.html'
    success_url = '/'
    form_class = TourStepForm
    model = Toursteps

    def get_context_data(self, **kwargs):
        context = super(CreateTourStepView, self).get_context_data(**kwargs)
        print(context['tour_id'])
        return context
class TourStepForm(forms.ModelForm):

    class Meta():
        model = Toursteps
        #fields = '__all__'
        exclude = ('tour',)

    def form_valid(self, form):
        if form.is_valid():
            form.instance.tour_id = self.request.GET("tour_id")

            form.instance.save()

            return HttpResponseRedirect(self.get_success_url())

    def get_success_url(self):
        return reverse('tour_detail', kwargs={'pk':form.instance.tour_id})

首先,您的
form\u valid()
get\u success\u url()
方法属于您的视图,而不属于您的表单

其次,
tour\u id
被传递给视图的
kwargs
,它不是查询参数,因此不在
self.request.GET
中。您可以在
self.kwargs
中找到它

第三,您需要从数据库中实际获取
Tour
,而不仅仅是分配
Tour\u id
。如果我愿意,我可以发布到任何
tour\u id
,并且不能保证
tour\u id
属于实际的
tour
对象。如果巡演不存在,则返回404。如果存在,则将其指定给巡更步骤


最后,您不应该分配和保存
form.instance
。您应该使用
step=form.save(commit=False)
获取实例,然后分配到
step
并保存
step

,因为
tour\u id
是您的url模式的一部分,它在视图的
kwargs
中(
self.kwargs
),而不是在
请求中。get
(这些是查询参数)。谢谢!这帮了大忙。self.kwargs就是答案,我基本上可以删除您提到的其余代码。不需要获取tour_id,因为检查已经通过外键构造在数据库级别上完成。检查已经完成,但在保存时会抛出数据库完整性错误,这不是一个很好的用户体验(还因为在日志中,除了用户输入外,实际上没有任何错误,因此会引发错误)。返回404是一种更好的体验。