..whatdoyoucallitanyway..
I have this model:
class Kaart(models.Model):
name = models.CharField(max_length=200, name="Kaardi peakiri", help_text="Sisesta kaardi pealkiri (maksimum tähemärkide arv on 38)", blank=False, null=False)
url = models.CharField(max_length=200, blank=False, null=False, name="Asukoha URL", help_text="Täisasukoht (http://www.domeen.ee/kaart/)")
kirjeldus = models.TextField(max_length=500, name="Kommentaar", help_text="Informatsioon / viide tegijale (mitte kohustuslik)")
Then i have this form:
class KaartForm(ModelForm):
class Meta:
model = Kaart
And i have this code in my template:
{% for field in form %}
<p>
<label>{{ field.label }}</label>
<em>{{ field.help_text }}</em>
{{ field }}
</p>
{% endfor %}
The problem is that both field.label and field.name display name, url, kirjeldus instead of the names i have set for them - "Kaardi pealkiri" etc. How do i get to use those instead?
You need to use verbose_name instead of name in your model.
name = models.CharField(max_length=200, verbose_name="Kaardi peakiri", help_text="Sisesta kaardi pealkiri (maksimum tähemärkide arv on 38)", blank=False, null=False)
See the docs. There is no option called name.
According to the documentation, the ModelForm's widget pulls its label value from the verbose_name attribute.
Related
I am using the following ModelForm:
class ListingQuoteForm(forms.ModelForm):
author_phone = forms.CharField(validators=[validate_phone_number])
content = forms.CharField(
label='Your message',
min_length=50,
widget=forms.Textarea(attrs={'rows': 4}),
help_text='Please provide a few details about your race and your requirements',
)
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
super().__init__(*args, **kwargs)
if user.is_authenticated:
self.fields['author_name'].initial = user.full_name(strict=True)
self.fields['author_email'].initial = user.email
self.fields['author_email'].disabled = True
class Meta:
model = QuoteRequest
fields = ('author_name', 'author_email', 'author_phone', 'content')
labels = {
'author_name': 'Your name',
'author_email': 'Your email',
'author_phone': 'Your phone number',
}
and rendering it in the following template:
{% load crispy_forms_tags %}
<div class="listing-section" id="quote-form">
<div class="listing-section-header">
{% if primary_category.quote_request_type == 'quote' %}
<h2>Request a quote</h2>
{% elif primary_category.quote_request_type == 'info' %}
<h2>Request more info</h2>
{% endif %}
</div>
<div class="listing-section-body">
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ quote_form.author_name|as_crispy_field }}
{{ quote_form.author_email|as_crispy_field }}
{{ quote_form.author_phone|as_crispy_field }}
{{ quote_form.content|as_crispy_field }}
<div class="form-group">
<button class="standard-button standard-button--submit" type="submit">Send</button>
</div>
</form>
</div>
</div>
When the content field min length validation fails, a message is displayed like so:
But when my custom phone number validation fails, the error displays under the field like so:
EDIT: Here's the QuoteRequest object as well:
class QuoteRequest(models.Model, ModelMixin):
SOURCES = (
('listing_page', 'Listing page'),
('dashboard_offers', 'Dashboard offers'),
('concierge', 'Concierge'),
)
source = models.CharField(max_length=18, null=True, blank=True, choices=SOURCES)
author = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL, related_name='quote_requests')
author_name = models.CharField(max_length=40)
author_email = models.EmailField()
author_phone = models.CharField(max_length=24, null=True, blank=True, validators=[validate_phone_number])
content = models.TextField()
category = models.ForeignKey(Category, null=True, blank=True, on_delete=models.CASCADE, related_name='quote_requests')
listing = models.ForeignKey(Listing, null=True, blank=True, on_delete=models.CASCADE, related_name='quote_requests')
offer = models.ForeignKey(Offer, null=True, blank=True, on_delete=models.SET_NULL, related_name='quote_requests')
race = models.ForeignKey(Race, null=True, blank=True, on_delete=models.SET_NULL, related_name='quote_requests')
approved = models.BooleanField(default=False)
date_created = models.DateTimeField(auto_now_add=True)
date_approved = models.DateTimeField(null=True)
How can I get my phone number validation error to display the same way the in-built min length validation does for the CharField?
You can use novalidate on form, to off default behavior of html5 of showing errors so that Django's errors can be shown.
So:
<form method="POST" enctype="multipart/form-data" novalidate>
{% csrf_token %}
{{ quote_form.author_name|as_crispy_field }}
{{ quote_form.author_email|as_crispy_field }}
{{ quote_form.author_phone|as_crispy_field }}
{{ quote_form.content|as_crispy_field }}
<div class="form-group">
<button class="standard-button standard-button--submit" type="submit">Send</button>
</div>
</form>
i have two models "product" and "brand"
product has brand field ManyToMany to link the products with the concerned brand
## models.py
class Product(models.Model):
title = models.CharField(max_length=120)
slug = models.SlugField(blank=True, unique=True)
description = models.TextField()
brand = models.ManyToManyField(Brand)
class Brand(models.Model):
title = models.CharField(max_length=250, unique=True)
slug = models.SlugField(max_length=250, unique=True)
description = models.TextField(blank=True)
## url.py
re_path(r'^brands/(?P<slug>[\w-]+)/$', BrandDetail.as_view(), name = 'branddetail'),
## views.py
class BrandDetail(DetailView):
queryset = Brand.objects.all()
template_name = "brands/brand.html"
## brands/brand.html
{{ object.title }} <br/>
{{ object.description }} <br/>
Now when am rendring brand.html it shows the brand title and description fine
My question is
if i want to render in the same page the list of products linked to specific brand "considering the brand slug already passed in the URL", how i can do that?
the class is DetailsView and it has only Brand details in the query set as shown!!
i need any solution not ne
You do not need a ListView for that, you can iterate over the product_set of the brand, like:
{{ object.title }} <br/>
{{ object.description }} <br/>
products:
{% for product in object.product_set.all %}
{{ product.title }} <br/>
{% endfor %}
I'm working in Django 2.2 trying to build a view for a database that compiles everything for a specific company (locations of all of their stores and notes on the companies) into a single view. I've tried methods in several different answers, but still cannot seem to get data from related foreign keys to show in the template.
models.py
class Company(models.Model):
name = models.CharField(max_length=30, primary_key=True)
official_name = models.CharField(max_length=50)
corporate_address1 = models.CharField(max_length=50)
corporate_address2 = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province = models.CharField(max_length=30)
country = models.ForeignKey('Country', on_delete=models.CASCADE)
slug = models.SlugField(max_length=30, unique=True)
def __str__(self):
return self.name
class Stores(models.Model):
store_name = models.CharField(max_length=30, primary_key=True)
owner = models.ForeignKey('Company', on_delete=models.CASCADE)
store_address1 = models.CharField(max_length=50)
store_address2 = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province = models.CharField(max_length=30)
country = models.ForeignKey('Country', on_delete=models.CASCADE)
type = models.CharField(max_length=30,choices=store_types)
slug = models.SlugField(max_length=30, unique=True)
def get_absolute_url(self):
return reverse("store-detail", kwargs={"slug": self.slug})
class notes(models.Model):
title = models.CharField(max_length=120)
content = models.TextField()
posted = models.DateTimeField(db_index=True, auto_now_add=True)
category = models.ForeignKey('Company', on_delete=models.CASCADE)
active = models.BooleanField(default=True)
def get_absolute_url(self):
return reverse("article-detail", kwargs={"id": self.id})
class Country(models.Model):
country = models.CharField(max_length=30,choices=countries,primary_key=True)
class Meta:
ordering = ["-country"]
db_table = 'country'
def __str__(self):
return self.country
views.py
class CompanyOverView(LoginRequiredMixin, DetailView):
model = Company
template_name = "company-overview.html"
slug_url_kwarg = 'slug'
query_pk_and_slug = True
pk_url_kwarg = "company.name"
template
<div align="center">
<p>{{ object.name }}<br>({{ object.official_name }})</p>
<p>{{ object.corporate_address1 }}<br>{{ object.corporate_address2 }}<br>
{{ object.city }}<br>{{ object.state_province }}<br>
{{ object.country }}</p>
</div>
<p>List of Stores</p>
<p>
{% for instance in object_list %}
{{ instance.company.stores.store_name }}
{{ instance.company.stores.store_address1 }}
{{ instance.company.stores.store_address2 }}
{{ instance.company.stores.city }}
{{ instance.company.stores.state_province }}
{{ instance.company.stores.country }}
{% endfor %}
</p>
<p>Notes</p>
<p>
{% for instance in object_list %}
{{ instance.company.notes.title }}
{{ instance.company.notes.posted }}
{% endfor %}
</p>
With the above code, the only thing that appears when you enter in the company's name is everything at the top (e.g."object.name" appears on the page as "Acme Corporation"). Nothing in the for loop appears on the web page.
Looking at the documentation, object_list is the default name for context unless specified. I have tried different combinations such as "for store_name in company.store_set.all" and other combinations I found in other posts, but none have worked. I've combed the documentation for everything related to foreign keys, but can't find a solution that works.
Thanks in advance if you can help.
No. object_list is the default context name in a ListView. But you have a DetailView, and you already know what the default context name is for those because you're already using it: object. You just need to iterate over the reverse relation from there:
{% for store in object.stores_set.all %}
{{ store.store_name }}
{{ store.store_address1 }}
...
{% endfor %}
I am having some trouble getting the values from a snippet, that I have included into a streamfield using a Snippet Chooser Block.
BioSnippet:
#register_snippet
class BioSnippet(models.Model):
name = models.CharField(max_length=200, null=True)
job_title = models.CharField(max_length=200, null=True, blank=True)
bio = RichTextField(blank=True)
image = models.ForeignKey(
'wagtailimages.Image',
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name='+',
verbose_name='Bio Image'
)
contact_email = models.CharField(max_length=50, null=True, blank=True)
contact_phone = models.CharField(max_length=50, null=True, blank=True)
panels = [
FieldPanel('name'),
FieldPanel('job_title'),
FieldPanel('bio'),
ImageChooserPanel('image'),
FieldPanel('contact_email'),
FieldPanel('contact_phone'),
]
def __str__(self):
return self.name
class Meta:
ordering = ['name',]
Bio Streamfield Definitions:
class BioInline(StructBlock):
bio = SnippetChooserBlock(BioSnippet)
class BioBlock(StructBlock):
overall_title = CharBlock(required=False)
bios = ListBlock(BioInline())
This all works, but when I get to the template, I cannot seem to access the values of the snippet
{% for b in child.value.bios %}
{{ b }}
<hr>
{{ b.name }}
{% endfor %}
the {{ b }} tag outputs:
bio
Sales Team
However {{ b.name }} outputs nothing. Neither does {{ b.values.name }} or any other permutation I can guess at. I suspect the values are just not being pulled down.
bios here is defined as a list of BioInline values, and so b in your template would be a BioInline value - which has a single property, bio (giving you the actual BioSnippet object). To get the name, you'd therefore have to use: {{ b.bio.name }}.
I don't think the BioInline object is actually gaining you anything though - you could instead define BioBlock as:
class BioBlock(StructBlock):
overall_title = CharBlock(required=False)
bios = ListBlock(SnippetChooserBlock(BioSnippet))
which would make bios a list of BioSnippets - {{ b.name }} would then work as expected.
Alternatively, you can use self.bios
In blocks.py you have to import the Snippet model (should have this allready):
from thebioapp.models import BioSnippet
And then use this model in the template itself
{% for b in self.bios %}
{{ b }}
<hr>
{{ b.name }}
{% endfor %}
The post is old, but as Wagtail is growing in popularity, I hope this will benefit others!
Here is my models.py:
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
utype = models.ForeignKey(Usertype)
school = models.ForeignKey(School)
courses = models.ManyToManyField(Course, related_name='c+', blank=True)
tutors = models.ManyToManyField(Course, related_name='t+', blank=True)
account = models.IntegerField(max_length=20, blank=True, null=True)
cellphone = models.BigIntegerField(max_length=14, unique=True, blank=True, null=True)
credits = models.FloatField(default=0.0)
transactions = models.ManyToManyField(Transaction, related_name='t+', blank=True)
verified = models.BooleanField(default=False)
paypalVerified = models.BooleanField(default=False)
applicationAccepted = models.BooleanField(default=False)
address = models.CharField(max_length=256, blank=True)
apartment = models.CharField(max_length=20, blank=True)
city = models.CharField(max_length=256, blank=True)
state = models.ForeignKey(State, null=True, blank=True)
zip = models.IntegerField(max_length=10, blank=True, null=True)
country = models.ForeignKey(Country, null=True, blank=True)
Here is my forms.py:
class ContactInfoForm(ModelForm):
def __init__(self, *args, **kwargs):
super(ContactInfoForm, self).__init__(*args, **kwargs)
self.fields['cellphone'].label = "Cell Phone Number"
self.fields['address'].label = "Address"
self.fields['apartment'].label = "Apartment"
self.fields['city'].label = "City"
self.fields['state'].label = "State"
self.fields['zip'].label = "Zip Code"
self.fields['country'].label = "Country"
class Meta:
model = UserProfile
fields = ('cellphone', 'address', 'apartment', 'city', 'state', 'zip', 'country')
Here is my views.py:
def profile(request):
c=getUserContext(request)
c['contactInfoForm'] = ContactInfoForm(instance = c['profile'])
if request.method == 'POST':
if request.POST['formType'] == "ContactInfo":
c['contactInfoForm'] = ContactInfoForm(request.POST, instance = c['profile'])
if c['contactInfoForm'].is_valid():
c['contactInfoForm'].save()
return render_to_response('profile.html', c)
If a user has entered data in all the fields in the ContactInfoForm, how do I loop over the fields in the form and display their values?
e.g. I want to display
Cell Phone Number 123-456-7890
Address 1 West Spring St
... etc.
I can't loop over the fields in my model because that includes many other fields that I do not want to display in the contactinfo section of the profile page.
I have been struggling on this for a while now and haven't gotten anywhere. If my question is not clear, please let me know and I will provide more information or try to restructure the question.
Here is how I am currently displaying the form to the user on profile.html:
{% for field in contactInfoForm %}
<tr>
<td class="fieldright">
<label class="inline">{{ field.label_tag }}</label>
</td>
<td>
{% if profile.field %}
<div class="field">
{{ profile.field }}
<input type="hidden" name="{{ field }}" id="id_{{ field }}" value={{ profile.field }}>
</div>
{% else %}
{{ field }}
{% endif %}
</td>
</tr>
{% endfor %}
EDIT: I changed profile.field to field.value and the value is being display now.
Iterate over the fields of the form, not the fields of the model.
If you want to hide other fields just use exclude in your form than fields
class Meta:
model = UserProfile
exclude = ('', '')