Как создать поле только для чтения, которое не может быть отредактировано пользователем в формах Django?

#python #django #forms #readonly #disable

#python #django #формы #только для чтения #отключить

Вопрос:

Я пытаюсь создать свой первый собственный проект на python django. То, что я делал до сих пор, — это простой магазин. Когда я нажимаю на это:

item_details.html

 <a href="{% url 'buy_item' pk=item.pk %}" class="submit">Kup teraz</a>
 

Я буду перенаправлен

urls.py

 path('buy/<int:pk>', ItemCreate.as_view(), name='buy_item')
 

В эту форму:

form.py

 class BuyForm(forms.ModelForm):

    class Meta:
        model = Order
        fields = (
        'item',
        'delivery',
        'price',
        'buyer',)
 

С этим представлением:

views.py

 class ItemCreate(CreateView):
    model = Order
    fields = ['item', 'price', 'buyer', 'delivery']

    def get_initial(self):
        item = get_object_or_404(Item, pk=self.kwargs['pk'])
        self.initial.update({
            'buyer': self.request.user,
            'price': item.price,
            'item': item.pk,
        })
        return super(ItemCreate, self).get_initial()
 

models.py

 from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User

class Category(models.Model):
    title = models.CharField(max_length=100)
    description = models.TextField()

    def __str__(self):
        return self.title
class Item(models.Model):
    seller = models.ForeignKey(User, on_delete=models.CASCADE)
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    title = models.CharField(max_length=100)
    price = models.FloatField(null=False, blank=False)
    img = models.ImageField(blank=True, null=True,
        upload_to='covers/%Y/%m/%D/')
    published_date = models.DateTimeField(default=timezone.now)
    def __str__(self):
        return self.title

class Supplier(models.Model):
    title = models.CharField(max_length=100)
    def __str__(self):
        return self.title

class Delivery(models.Model):
    title = models.ForeignKey(Supplier, on_delete=models.CASCADE)
    price_of_delivery = models.FloatField(null=False, blank=False)
    def __str__(self):
        return self.title

class Order(models.Model):
    item = models.ForeignKey(Item, on_delete=models.CASCADE)
    delivery = models.ForeignKey(Delivery, on_delete=models.CASCADE)
    order_date = models.DateTimeField(default=timezone.now)
    buyer = models.ForeignKey(User, on_delete=models.CASCADE)
    price = models.FloatField(null=False, blank=False)
    def __str__(self):
        return self.item
 

Поскольку исходные данные не должны редактироваться пользователем, я бы хотел сделать их доступными только для чтения.

То, что я пробовал до сих пор, это:

 class BuyForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
       super(BuyForm, self).__init__(*args, **kwargs)
       self.fields['buyer'].widget.attrs['readonly'] = True    

    class Meta:
        model = Order
        fields = (
        'item',
        'delivery',
        'price',
        'buyer',)
 

В моей консоли нет ошибок, но и результатов нет.

Мой order_form.html выглядит так , что:

 {% extends 'shop/base.html' %}
{% block content %}

<div align="center">
    <h1>Buy item</h1>
    <form method="POST" class="post-form">{% csrf_token %}
        {{ form.as_p }}
        <button type="submit" class="save btn btn-default">Buy</button>
    </form>
</div>
<
{% endblock %}
 

Что мне сделать, чтобы «покупатель», «цена» и «товар» были доступны только для чтения?

Ответ №1:

Все остальные ответы отличные и правильные, но это не решило проблему, когда я создавал ваш пример.

Реальная проблема в том, что ваше представление никогда не использует вашу форму в первую очередь — вот почему переопределение атрибутов ничего не дало!

Подробнее о представлениях на основе классов с пользовательскими формами из django docs

views.py

 from django.shortcuts import get_object_or_404
from django.views.generic import CreateView
from .models import Item
from .forms import BuyForm

class ItemCreate(CreateView):
    form_class = BuyForm
    template_name = 'order_form.html'
    success_url = '/thanks/'

    def get_initial(self):
        item = get_object_or_404(Item, pk=self.kwargs['pk'])
        self.initial.update({
            'buyer': self.request.user.id,
            'price': item.price,
            'item': item.pk,
        })
        return super(ItemCreate, self).get_initial()
 

forms.py

 from django import forms
from .models import Order


class BuyForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(BuyForm, self).__init__(*args, **kwargs)
        self.fields['buyer'].disabled = True

    class Meta:
        model = Order
        fields = (
            'item',
            'delivery',
            'price',
            'buyer',)
 

Комментарии:

1. Поля отключены, но он показывает «Выберите правильный выбор. Этот выбор не является одним из доступных вариантов. » и я не могу отправить свой заказ.

2. @Eliro Вам нужно указать user.id инициалы, а не просто user . Я обновил свой ответ.

Ответ №2:

попробуйте это:

 class BuyForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
       super(BuyForm, self).__init__(*args, **kwargs)
       self.fields['buyer'].required = False
       self.fields['buyer'].widget.attrs['disabled'] = "disabled" 

       ...

    def clean_buyer(self):
        instance = getattr(self, 'instance', None)
        if instance:
            return instance.buyer
        else:
            return self.cleaned_data.get('buyer', None)
 

но файл с отключенным attr будет отправлять blank данные. Вот почему мы переопределяем clean метод, чтобы установить значение поля таким, какое было изначально в экземпляре.

Комментарии:

1. Несмотря на использование функции clean, она публикует пустые данные.

Ответ №3:

То, что вы ищете, — это disabled атрибут formfield:
https://docs.djangoproject.com/en/2.2/ref/forms/fields/#disabled

Ответ №4:

Другой подход заключается в том, чтобы сделать их скрытыми полями. Добавьте это в Meta…

 class Meta:
    widgets = {
        'buyer': forms.HiddenInput(),
        'price': forms.HiddenInput(),
        'item': forms.HiddenInput(),
    }
 

Комментарии:

1. Никаких результатов и никаких ошибок. Я все еще могу редактировать исходные данные. Кстати — я бы хотел сделать поля только для чтения. Как я могу ПРОЧИТАТЬ скрытый ввод?