繁体   English   中英

Django 3 - 带有初始外键字段的 CreateView

[英]Django 3 - CreateView with initial ForeignKey field

我正在尝试在 Django 3 上创建一个“餐厅评级”应用程序。我设置了以下模型:

# Table storing the different restaurants
class Restaurant(models.Model):
    restaurant_name = models.CharField(max_length=200, unique=True)
    restaurant_address = models.CharField(max_length=200)
    restaurant_street_number = models.CharField(max_length=10)
    restaurant_city = models.CharField(max_length=200)
    restaurant_cuisine_type = models.CharField(max_length=200)
    def __str__(self):
        return self.restaurant_name + ' - ' + self.restaurant_city


class UserReview(models.Model):
    # Defining the possible grades
    Grade_1 = 1
    Grade_2 = 2
    Grade_3 = 3
    Grade_4 = 4
    Grade_5 = 5
    # All those grades will sit under Review_Grade to appear in choices
    Review_Grade = (
        (1, '1'),
        (2, '2'),
        (3, '3'),
        (4, '4'),
        (5, '5')
    )
    restaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE)
    user_review_grade = models.IntegerField(default=None, choices=Review_Grade) # default=None pour eviter d'avoir un bouton vide sur ma template
    user_review_comment = models.CharField(max_length=1500)
    def get_absolute_url(self):
        return reverse('restaurants:reviews', args=[self.id])

这是我正在使用的表格:

# Form for user reviews per restaurant
class UserReviewForm(forms.ModelForm):
    class Meta:
        model = UserReview
        #  restaurant = forms.ModelChoiceField(queryset=Restaurant.objects.filter(pk=id))
        fields = [
            'restaurant',
            'user_review_grade',
            'user_review_comment'
        ]
        widgets = {
            'restaurant': forms.HiddenInput,
            'user_review_grade': forms.RadioSelect,
            'user_review_comment': forms.Textarea
        }
        labels = {
            'user_review_grade': 'Chose a satisfaction level:',
            'user_review_comment': 'And write your comments:'
        }

这是我的网址:

app_name = 'restaurants'
urlpatterns = [
    # ex: /restaurants/
    path('', views.index, name='index'),

    # ex: /restaurants/15
    path('<int:restaurant_id>/', views.details, name='details'),

    # ex: /restaurants/test
    path('<int:restaurant_id>/test', views.Test.as_view(), name='test')

]

模板:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>TEST</title>
</head>
<body>
<h1>Write a review for this restaurant:</h1>
<form method="post">
    {% csrf_token %}
    <input type="Hidden" name="restaurant" value="{{restaurant.restaurant_id}}">
    {{ form.as_p }}
    <br>
    <input type="submit" value="Submit">
</form>
</body>
</html>

最后我的观点:

# Test class to be renamed posts reviews as it should
class Test (CreateView):
    template_name = 'restaurants/TEST.html'
    form_class = UserReviewForm

    # Get the initial information needed for the form to function: restaurant field
    def get_initial(self, restaurant_id, *args, **kwargs):
        initial = super(Test, self).get_initial(**kwargs)
        initial['restaurant'] = 9
        return initial()

    # Post the data into the DB
    def post(self, request, *args, **kwargs):
        form = UserReviewForm(request.POST)
        if form.is_valid():
            review = form.save()
            print(review)  # Print so I cna see in cmd prompt that something posts as it should
            review.save()
        return render(request, 'restaurants/reviews.html', {'form': form})

我面临一个问题,因为当我将初始定义为积分器时(假设为 9 - 因为我将它用于测试我的表单是否实际发布),它在数据库中发布了 id=9 的餐厅的评论没有问题但是我无法根据我们访问的餐厅页面自动填充 restaurant_id。

我尝试了以下以及在这里和那里找到的其他一些“技巧”,但似乎没有任何效果......

# Test class to be renamed later IF it works...
class Test (CreateView):
    template_name = 'restaurants/TEST.html'
    form_class = UserReviewForm

    # Get the initial information needed for the form to function: restaurant field
    def get_initial(self, restaurant_id, *args, **kwargs):
        restaurant = get_object_or_404(Restaurant, pk=restaurant_id)
        initial = super(Test, self).get_initial(**kwargs)
        initial['restaurant'] = self.request.restaurant.pk  
        return initial()

    # Post the data into the DB
    def post(self, request, *args, **kwargs):
        form = UserReviewForm(request.POST)
        if form.is_valid():
            review = form.save()
            print(review)  # Print so I cna see in cmd prompt that something posts as it should
            review.save()
        return render(request, 'restaurants/reviews.html', {'form': form})

任何帮助将不胜感激指出我正确的方向:)

您可以获取restaurant_id在网址参数self.kwargs['restaurant_id'] 所以你可以:

class Test(CreateView):

    def get_initial(self, *args, **kwargs):
        initial = super(Test, self).get_initial(**kwargs)
        initial['restaurant'] = self.kwargs['restaurant_id']  
        return initial

    # …

话虽如此,无论如何以某种形式存储它是相当奇怪的。 当表单有效时,您可以简单地设置它。 所以我们定义没有餐厅的表单:

class UserReviewForm(forms.ModelForm):
    class Meta:
        model = UserReview
        fields = [
            'user_review_grade',
            'user_review_comment'
        ]
        widgets = {
            'user_review_grade': forms.RadioSelect,
            'user_review_comment': forms.Textarea
        }
        labels = {
            'user_review_grade': 'Chose a satisfaction level:',
            'user_review_comment': 'And write your comments:'
        }

然后在CreateView ,我们设置该实例的restaurant

class Test(CreateView):
    template_name = 'restaurants/TEST.html'
    model = UserReview
    form_class = UserReviewForm
    success_url = …

    def form_valid(self, form):
        form.instance.restaurant_id = self.kwargs['restaurant_id']
        super().form_valid(form)

您在这里需要指定一个success_url ,如果提交成功,它将重定向到该地址。 如果 POST 成功,您需要进行重定向以实现Post/Redirect/Get模式 [wiki]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM