I have a date of birth field in my model but why it's not showing up in the template when I render it? The date_of_birth is inside Teacher model. And Do you have any good idea on date_of_birth field? Because right now I'm using charfield for that so I need to convert the DateInput to string so that I can add it into charfield.
here is my models.py
class Teacher(models.Model):
user = models.OneToOneField(CustomUser, on_delete=models.CASCADE, primary_key=True)
date_of_birth = models.CharField(max_length=100)
teacher_type = models.CharField(max_length=50
def __str__(self):
return self.user.email
my forms.py
class TeacherRegisterForm(UserCreationForm):
date_attr = {'class': 'form-control', 'id': 'dateofbirth-register', 'type': 'date'}
date_of_birth = forms.DateField(widget = forms.DateInput(attrs=date_attr))
teacher_type = forms.ChoiceField(label=_('Teacher Type'), choices=type_choice
class Meta(UserCreationForm):
model = CustomUser
fields = ['date_of_birth', 'teacher_type']
def save(self, commit=True):
user = super().save(commit=False)
user.is_teacher = True
user.save()
teacher = Teacher.objects.create(user=user)
teacher.date_of_birth += str(self.cleaned_data.get('date_of_birth'))
teacher.teacher_type += self.cleaned_data.get('teacher_type')
return user
views.py
#login_required
#teacher_required
def teacherInfoView(request):
template_name = "attendance/content/teacher/teacher_info.html"
teacher_info = Teacher.objects.filter(user=request.user)
context = {'teacher_info': teacher_info}
return render(request, template_name, context)
template
{% for info in teacher_info %}
<!-- firstname -->
<div class="row">
<div class="ml-5 mr-auto">
<h5>Name : {{ info.user.first_name }} {{ info.user.last_name }}</h5>
</div>
<div class="ml-5">
<h5>Email : {{ info.user.email }}</h5>
</div>
</div>
<div class="row">
<div class="ml-5">
<h5>Date Of Birth : {{ info.date_of_birth }}</h5>
</div>
<div class="ml-5">
<h5>Gender : {{ info.user.gender }}</h5>
</div>
</div>
{% endfor %}
Related
This is my patient model and forms:
class Patient(models.Model):
def __str__(self):
return f"{self.first_name} {self.last_name}"
doctor = models.ForeignKey(User, on_delete=models.CASCADE)
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
sex = models.CharField(max_length=20)
phone = models.IntegerField()
birth_date = models.DateField()
class PatientForm(forms.ModelForm):
BIRTH_YEAR_CHOICES = []
for years in range(1900,2021):
BIRTH_YEAR_CHOICES.append(str(years))
sex_choice = [('1', 'Homme'), ('2', 'Femme')]
sex = forms.ChoiceField(widget=forms.Select(attrs={'class':'form-control'}), choices=sex_choice)
doctor = forms.ModelChoiceField(widget=forms.Select(attrs={'class': 'form-control'}),queryset=Patient.objects.all())
first_name = forms.CharField(widget= forms.TextInput(attrs={'class':'form-control'}))
last_name = forms.CharField(widget= forms.TextInput(attrs={'class':'form-control'}))
phone = forms.CharField(widget= forms.TextInput(attrs={'class':'form-control'}))
birth_date = forms.DateField(widget=forms.SelectDateWidget(years=BIRTH_YEAR_CHOICES,attrs={'class': 'form-control'}))
class Meta:
model = Patient
fields = '__all__'
def __init__(self, *args, **kwargs):
super(PatientForm, self).__init__(*args, **kwargs)
self.fields['birth_date'].input_formats = ('%Y-%m-%d')
And this register.html:
<form method="POST">{% csrf_token %}
<div class="input-group">
<span class="input-group-text">Prénom:</span>
{{form.first_name}}
</div>
<div class="input-group">
<span class="input-group-text">Nom:</span>
{{form.last_name}}
</div>
<div class="input-group">
<span class="input-group-text">Sex</span>
{{form.sex}}
</div>
<div class="input-group">
<span class="input-group-text">Telephone</span>
{{form.phone}}
</div>
<div class="input-group">
<span class="input-group-text">Date de naissance</span>
{{form.birth_date}}
</div>
<div class="input-group">
<span class="input-group-text">Docteur</span>
<select name="doctor_choice">
{% for doctor in doctors %}
<option value="{{doctor.pk}}">{{doctor.first_name}} {{doctor.last_name}}</option>
{% endfor %}
</select>
</div>
The attrs={'class':'form-control'} is working at all the fields except the doctor field which is a ForeignKey in Patient model. So when I search about it I found that they use doctor = forms.ModelChoiceField but still dosen't work and 'class':'form-control' isn't working yet
My models:
class Comment(models.Model):
product = models.ForeignKey(Product ,on_delete=models.CASCADE, related_name='comments')
user = models.ForeignKey(User ,on_delete=models.CASCADE, max_length=80, related_name='comments_user')
body = models.TextField()
created_on = jmodels.jDateField(auto_now_add=True)
created_on_time = models.TimeField(auto_now_add=True,null=True)
active = models.BooleanField(default=False)
class Meta:
ordering = ['created_on']
def __str__(self):
return 'Comment {} by {}'.format(self.body, self.user)
class Rating(models.Model):
product = models.ForeignKey(Product ,on_delete=models.CASCADE)
user = models.ForeignKey(User ,on_delete=models.CASCADE)
score = models.IntegerField(default=0,
validators=[
MaxValueValidator(5),
MinValueValidator(0),
]
)
def __str__(self):
return 'rate {} by {} for {}'.format(self.score, self.user, self.product)
In product single page, I have comments part that I want show user rating if that user put comment in next of username and comment date.
My views :
def product_details(request, category_url, subcategory_url, product_url):
product = get_object_or_404(Product, product_url=product_url)
stocks = Stock.objects.filter(product=product)
rate = Rating.objects.filter(product=product, user=request.user)
all_rates = Rating.objects.filter(product=product)
all_rate_count = Rating.objects.filter(product=product).count()
all_rate = sum([all_rate.score for all_rate in all_rates])
all_rate = all_rate/all_rate_count
all_rate = all_rate*100/5
comments = product.comments.filter(product=product, active=True)
if request.method == "POST":
body = request.POST['body']
new_comment = Comment(user=request.user,product=product, body=body)
new_comment.save()
message_good = "نظر شما با موفقیت ثبت شد بعد از برسی نمایش داده میشود!"
ctx = {'product':product, 'stocks':stocks, 'rate':rate, 'all_rate':all_rate,
'comments':comments,
'message_good':message_good,
'all_rate_count':all_rate_count}
return render(request, 'products/product_details.html', ctx)
ctx = {'product':product, 'stocks':stocks, 'rate':rate, 'all_rate':all_rate,
'comments':comments,
'all_rate_count':all_rate_count}
return render(request, 'products/product_details.html', ctx)
And my html :
{% for comment in comments %}
<div class="comments" style="padding: 10px;">
<p class="font-weight-bold">
{{ comment.user }}
<span class=" text-muted font-weight-normal">
{{ comment.created_on }}
</span>
<span class=" text-muted font-weight-normal">
{{ comment.created_on_time|date:"G:i" }}
</span>
</p>
{{ comment.body | linebreaks }}
</div>
{% endfor %}
I updated my codes, and showed my views and my single html
so if please can help me about showing product rate by user for each comment that filtered by user.
or any better suggestion for other ways about rating or showing comments for single product page. thanks for helping
I would add a unique_together constraint to enforce that a user can only leave a single rating for a product.
class Rating(models.Model):
product = models.ForeignKey(Product ,on_delete=models.CASCADE)
user = models.ForeignKey(User ,on_delete=models.CASCADE)
score = models.IntegerField(default=0,
validators=[
MaxValueValidator(5),
MinValueValidator(0),
]
)
class Meta:
unique_together = ('product', 'user')
def __str__(self):
return 'rate {} by {} for {}'.format(self.score, self.user, self.product)
In your views, since you will only have one rating for a product per user.
rate = Rating.objects.get(product=product, user=request.user)
In your templates:
{% for comment in comments %}
<div class="comments" style="padding: 10px;">
<p class="font-weight-bold">
{{ comment.user }}
<span class=" text-muted font-weight-normal">
{{ comment.created_on }}
</span>
<span class=" text-muted font-weight-normal">
{{ comment.created_on_time|date:"G:i" }}
</span>
</p>
{{ comment.body | linebreaks }}
{{ rate.score }}
</div>
{% endfor %}
I have created small stock web app.
I created a stock model with unique part_number field. In my update template I send all item information to be displayed. Then I get an error in the part_number field that it is already there.
How can I avoid this validation for that part_number only?
I mean for same part_number suppose validation will not work. But if I modified to another part_number that already exists I get an error that it's being duplicated.
Model:
class Stock(models.Model):
part_number = models.CharField(max_length=30, blank=False, unique=True)
part_name = models.CharField(max_length=70)
quantity = models.IntegerField(blank=False)
location = models.CharField(max_length=3, blank=True)
model = models.CharField(max_length=40, blank=True, null=True, default="")
min_quantity = models.IntegerField(unique=False, blank=True, default=0)
max_quantity = models.IntegerField(unique=False, blank=True, default=0)
class Meta:
ordering = ['part_number']
def clean(self):
self.part_number = self.part_number.upper()
def __str__(self):
return self.part_number
Form.py:
class StockUpdateModelForm(forms.ModelForm):
class Meta:
model = models.Stock
fields = ['part_name', 'quantity', 'location','part_number']
views.py:
def stock_update_form_view(request, part_id):
item = Stock.objects.get(id=part_id)
item_id = Stock.objects.get(id=part_id).pk
form = StockUpdateModelForm({
'part_number' : item.part_number,
'part_name' : item.part_name,
'quantity' : item.quantity,
'location' : item.location
})
if request.method == 'POST':
form = StockUpdateModelForm(request.POST)
if form.is_valid():
s = Stock.objects.get(pk=item_id)
s.part_name = form.cleaned_data['part_name']
s.part_number = form.cleaned_data['part_number']
s.quantity = form.cleaned_data['quantity']
s.location = form.cleaned_data['location']
print("form is valid")
s.save()
return redirect('/stock/')
return render(request, 'stock/stock_update.html', {'form': form, 'pn': item.part_number})
html:
<form class="bg-light shadow" method="POST">
<div style="margin-left:10%; margin-top:30px">
<h4>Part Number : {{ pn }}</h4>
</div>
<hr style="width:100%">
{% csrf_token %}
<div class="row" style="margin-left:30px; margin-top:40px ">
<div class="col-sm-4" style="margin-left:6%">
{{ form.part_name|as_crispy_field }}
</div>
<div class="col-sm-4" style="margin-left:15%">
{{ form.part_number|as_crispy_field }}
</div>
<div class="col-sm-4" style="margin-left:6%">
{{ form.quantity|as_crispy_field }}
</div>
<div class="col-sm-4" style="margin-left:15%">
{{ form.location|as_crispy_field }}
</div>
<div class="col-sm-4" style="height: 100px; margin-top:30px ; margin-left:6%">
<hr style="width:100%">
<input class="btn btn-primary" type="submit" value="Save"
style="width: 150px;">
</div>
</div>
</form>
try this
if request.method == 'POST':
form = StockUpdateModelForm(request.POST, instance=item)
if form.is_valid():
form.save()
I changed ModelChoiceField to be shown as a TextInput.
I have a field named 'filename' of this type: models.ForeignKey('Filename', on_delete=models.SET_NULL, null=True, blank=True) in a class as follow:
models.py
class Event(models.Model):
name = models.CharField('Name', max_length=100, blank=True, default='')
filename = models.ForeignKey('Filename', on_delete=models.SET_NULL, null=True, blank=True)
class Filename(models.Model):
name = models.CharField('Name', max_length=50)
def __str__(self):
return self.nome
This is part of my 'forms.py' I use show form in frontend after defining the template (myappname/templates/myappname/event_edit.html)
forms.py
class EventEditForm(forms.ModelForm):
def __init__(self, data=None, *args, **kwargs):
if data is not None:
data = data.copy()
if data['filename']:
f, f_created = Filename.objects.get_or_create(nome=data['filename'])
data['filename'] = m.id
super(EventEditForm, self).__init__(data=data, *args, **kwargs)
self.fields['filename'] = forms.ModelChoiceField(queryset=Filename.objects.all(), widget=forms.TextInput(attrs={'class': 'form-control', 'value':self.instance.filename}))
self.fields['filename'].required = False
class Meta:
model = Event
fields = ['name', 'filename']
and this is my event_edit.html:
<form method="post" class="form-horizontal">
{% csrf_token %}
{% for field in event_form %}
<div class="form-group form-group-lg">
<label for="{{ field.id_for_label }}" class="col-sm-2 control-label">{{field.label}}</label>
<div class="col-sm-6">
{{ field }}
</div>
<div class="col-sm-4">
{{ field.errors }}
</div>
</div>
{% endfor %}
<div class="form-group">
<div class="col-sm-10">
<button type="submit" class="btn btn-primary btn-lg center-block">Save</button>
</div>
</div>
</form>
The problem is that if I override ModelChoiceField to be a TextInput the 'filename' field shows id instead of showing field name.
Otherwise, If I leave it as a Choice Field it correctly shows value instead of id.
How can I solve this issue?
Based on your comments and the code in EventEditForm, you want a form that will:
display the Event.name and the linked Filename.name
use the submitted name to update Event.name
use the submitted filename to lookup or create a Filename and update Event.filename
This should work:
class EventEditForm(forms.ModelForm):
"""
Calling form.save() will:
* update the Event.name
* update the Event.filename with a Filename instance
found or created using the supplied name
"""
fname = forms.CharField(
label='Filename',
required=False,
widget=forms.TextInput(attrs={'class': 'form-control'}),
)
class Meta:
model = Event
fields = ['name',]
widgets = {
'name': forms.TextInput(attrs={'class': 'form-control'}),
}
def __init__(self, *args, **kwargs):
super(EventEditForm, self).__init__(*args, **kwargs)
self.initial['fname'] = self.instance.filename
def save(self, commit=True):
instance = super(EventEditForm, self).save(commit=False)
cleaned_fname = self.cleaned_data['fname']
if cleaned_fname:
f, f_created = Filename.objects.get_or_create(name=cleaned_fname)
instance.filename = f
else:
instance.filename = None
if commit:
instance.save()
return instance
I'm getting an issue with my Django form validation. I would like to display form errors and make all fields required. I don't know why my fields can accept blank while blank is not defined in my model file.
This is my model :
class Customer(models.Model):
email = models.CharField(max_length=150, verbose_name=_('e-mail'), null=False)
first_name = models.CharField(max_length=70, verbose_name=_('first name'), null=False)
last_name = models.CharField(max_length=70, verbose_name=_('last name'), null=False)
country = models.ForeignKey(Country, verbose_name=_('country'))
institution = models.CharField(max_length=255, verbose_name=_('institution'), null=True)
creation_date = models.DateTimeField(auto_now_add=True, verbose_name=_('creation date'), null=False)
modification_date = models.DateTimeField(auto_now=True, verbose_name=_('modification date'), null=False)
class Meta:
verbose_name = _('customer')
verbose_name_plural = _('customer')
def __str__(self):
return f"{self.email}"
This is my form :
class CustomerForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(CustomerForm, self).__init__(*args, **kwargs)
self.fields['country'].empty_label = _('Select a country')
self.fields['country'].queryset = self.fields['country'].queryset.order_by(
'name')
for key in self.fields:
self.fields[key].required = True
class Meta:
model = Customer
fields = ['email', 'first_name', 'last_name', 'country', 'institution']
widgets = {
'email': forms.TextInput(attrs={'placeholder': _('name#example.com')}),
'first_name': forms.TextInput(attrs={'placeholder': _('First Name')}),
'last_name': forms.TextInput(attrs={'placeholder': _('Last Name')}),
'institution': forms.TextInput(attrs={'placeholder': _('Agency, company, academic or other affiliation')}),
}
You can find here my view with Django CBV :
class HomeView(CreateView):
""" Render the home page """
template_name = 'app/index.html'
form_class = CustomerForm
def get_context_data(self, **kwargs):
kwargs['document_list'] = Document.objects.all().order_by('publication__category__name')
return super(HomeView, self).get_context_data(**kwargs)
def post(self, request, *args, **kwargs):
if request.method != 'POST':
return HttpResponseRedirect(self.get_success_url())
form = self.form_class(request.POST)
email = request.POST['email']
country_id = request.POST['country']
country = Country.objects.get(id=country_id)
for checkbox in request.POST.getlist('DocumentChoice'):
document = Document.objects.get(id=checkbox)
token = self.gen_token(email, document.edqm_id)
Download.objects.create(email=email, country=country, pub_id=checkbox, token=token,
expiration_date=now + timedelta(minutes=10))
if not form.is_valid():
print('form invalid')
continue
return HttpResponseRedirect(self.get_success_url())
And finally my template :
{% extends "publication/base_backend.html" %}
{% load staticfiles %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block main %}
<form method="post" id="customerform" novalidate>
{% csrf_token %}
<h3>{% trans 'Your information' %}</h3>
<hr>
<div class="col-sm-12 col-md-12 col-lg-12">
{{ form.email|as_crispy_field:"bootstrap" }}
</div>
<br />
<br />
<br />
<br />
<div class="alert alert-info col-sm-12 col-md-12 col-lg-12" role="alert">
<small>{% trans "The fields below are optional if you have already requested a publication:" %}</small>
</div>
<div class="col-sm-5 col-md-5 col-lg-5">
{{ form.first_name|as_crispy_field:"bootstrap" }}<br>
{{ form.country|as_crispy_field:"bootstrap" }}
</div>
<div class="col-sm-5 col-md-5 col-lg-5 col-sm-offset-2 col-md-offset-2 col-lg-offset-2">
{{ form.last_name|as_crispy_field:"bootstrap" }}<br>
{{ form.institution|as_crispy_field:"bootstrap" }}
</div>
<div class="col-md-12">
<br />
<br />
</div>
<input type="submit" class="btn btn-default" value="{% trans 'Save' %}"/>
{% trans 'Cancel' %}
</form>
Issues :
According to required fields, I don't know why my form doesn't display missing values errors when I want to submit it.
I have to display fields as shown in my template because I have to make bootstrap design.
In order to display form errors, I have to write {{form.email.errors}} for example but nothing appears.
Thank you by advance