I'm trying to create my first own project in python django. What I'v done so far is a simple shop. When I click this:
item_details.html
<a href="{% url 'buy_item' pk=item.pk %}" class="submit">Kup teraz</a>
I will be redirected
path('buy/<int:pk>', ItemCreate.as_view(), name='buy_item')
To this form:
class BuyForm(forms.ModelForm):
class Meta:
model = Order
fields = (
'item',
'delivery',
'price',
'buyer',)
With this view:
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()
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
Because the initial data shouldn't be edited by user, I'd like to make them readonly.
What I've tried so far is:
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',)
No errors in my console but also there's no results.
My order_form.html looks that:
{% 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 %}
What should I do to make "buyer", "price" and the "item" readonly?
All other answers are great and correct, but that didn't solve the problem when I created your example.
Actual problem is that your view never use your form in a first place - that's why overriding attributes did nothing!
More about class-based views with custom forms from 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',)
try this:
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)
but the filed with disabled attr will post blank
data. That why we override the clean
method to set the field's value to be what was originally in the instance.
What you are looking for is a formfield's disabled
attribute:
https://docs.djangoproject.com/en/2.2/ref/forms/fields/#disabled
Another approach is to make them hidden fields. Add this to the Meta...
class Meta:
widgets = {
'buyer': forms.HiddenInput(),
'price': forms.HiddenInput(),
'item': forms.HiddenInput(),
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.