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