Hello I am trying to display work orders from my mysql database to show up in an email. However There is a problem because work_orders is a part of my Class Invoice manytomany field. This gives me this error.
'ManyRelatedManager' object has no attribute 'description'
I not really sure what the problem is. Here are some part of my app that could be helpful.
#views.py
#login_required
def invoice_mail(request, id=1):
invoices_list = Invoice.objects.filter(pk=id)
invoice = get_object_or_404(Invoice, pk=id)
client = invoices_list[0].client
invoice_no = invoices_list[0].invoice_no
date = invoices_list[0].date
work_orders = invoices_list[0].work_orders
t = loader.get_template('registration/email.txt')
c = Context({
'client': client.company,
'address':client.address,
'city': client.city,
'postcode': client.postcode,
'email': client.email,
'date': date,
'invoice_no': invoice_no,
'work_orders': work_orders.description,
})
send_mail('Welcome to My Project', t.render(c), 'jess#example.com', ['tom#example.com'], fail_silently=False)
return render_to_response('sent_email.html', locals(), context_instance=RequestContext(request))
email.txt
INVOICE
Bill to: INVOICE # {{invoice_no}}
{{client}} DATE: {{date}}
{{address}}
{{city}}
{{postcode}}
{{email}}
quantity item Description
{{work_orders.description}}
Unless you added a description field to the manager, the attribute doesn't exist (as it says).
Maybe you want to use
for order in work_orders.all():
print order.description
or in a template
{% for order in work_orders.all }}
{{ order.description }}
{% endfor %}
And maybe you need to change it in the context
'work_orders': work_orders
work_orders is not a list. It's an accessor/ORM Manager for your many-to-many field.
To get the actual work orders, you need to do work_orders.all() (or .filter(foo=bar)) and then iterate over each work order you get back to format them decently for including in an email
Related
I created a simple CRUD app using Flask and FlaskForm. I have a table where the last name, first name, birthdate, and sex are displayed coming from the database. Beside each name are links labeled as delete and update. When you click on update, you are routed to the update page with a form where the form fields corresponding to the last name, first name, birthdate, and sex should be populated. Sex is a select field with options Male and Female, how do I populate this based from the database? Using FlaskForm, I tried {{form.sex(value=user_to_update.sex)}} but it does not populate.
Here is my Update route:
#app.route('/update/<int:id>', methods=['GET', 'POST'])
def update(id):
form = Form()
user_to_update = TblPatient.query.get_or_404(id)
if request.method == 'POST':
user_to_update.lastname = form.lastname.data
user_to_update.firstname = form.firstname.data
user_to_update.birthdate = form.birthdate.data
user_to_update.sex = form.sex.data
db.session.commit()
return redirect(url_for('add_record'))
return render_template('update.html', form=form, user_to_update=user_to_update)
Here is the FlaskForm part:
class Form(FlaskForm):
lastname = StringField('Last Name', validators=[DataRequired()])
firstname = StringField('Firstname', validators=[DataRequired()])
birthdate = DateField('Date of Birth', format='%Y-%m-%d', validators=[DataRequired()])
sex = SelectField('Sex',
choices=['Select', 'Male', 'Female'],
default='Select',
validators=[DataRequired()])
submit = SubmitField('submit')
Here is my update.html where the form fields except for sex are populated:
<form action="{{request.path}}" method="post">
{{form.hidden_tag()}}
<fieldset>
<legend>Patient Info</legend>
<p>
{{form.lastname.label}} <br/>
{{form.lastname(value=user_to_update.lastname, size=30)}}
</p>
<p>
{{form.firstname.label}} <br/>
{{form.firstname(value=user_to_update.firstname, size=30)}}
</p>
<p>
{{form.birthdate.label}} <br/>
{{form.birthdate(value=user_to_update.birthdate)}}
</p>
<p>
{{form.sex.label}} <br/>
{{form.sex(value=user_to_update.sex)}}
</p>
</fieldset>
<br/>
{{form.submit}}
</form>
This is the home page:
When I click on update, it redirects me to the update page in question. How do I populate the sex field based on FlaskForm?
If the names of the database columns match those of the form's input fields, you can simply pass the database object to the form and the fields will be automatically populated. You do not need to pass the data to the input fields within the template.
patient = Patient.query.get_or_404(patient_id)
form = PatientForm(request.form, obj=patient)
An alternative to using the obj attribute is the assignment using the data attribute. See the documentation for the Form class.
In addition, you can then use the populate_obj function to transfer the form data to the database object.
form.populate_obj(patient)
The following example shows you how your endpoint should look like.
The patient is read from the database and assigned to the form. If the request is of type POST and the entries have been validated successfully, the patient data will be updated using the form.
#app.route('/update/<int:patient_id>', methods=['GET', 'POST'])
def update(patient_id):
patient = Patient.query.get_or_404(patient_id)
form = PatientForm(request.form, obj=patient)
if form.validate_on_submit():
form.populate_obj(patient)
db.session.commit()
return redirect(url_for('add_record'))
return render_template('update.html', **locals())
I would like to do:
I am trying to create a form input on a detail view that will update a particular data column ('status') of the detailed model instance. Here is a picture of what I have in mind:
The selector would display the current status and the user could change it and update from the detail view without having to access the UpdateView.
my idea here would be to have this happen:
1. On submit, get the new user entered value.
2. get the model instance of the currently detailed class
3. assign the model instance attribute as the user entered value
4. save the model instance
I've tried: I don't know if this is the best way to do this but i've been trying to create an AJAX call, mostly by looking for examples online.
Results: Terminal shows Post on submit: "[19/Nov/2019 17:50:33] "POST /task/edit/4 HTTP/1.1" 200 41256". However, the data is not saved to the db. On refresh, the selector returns to previously saved status.
The console shows: "script is connected", and "Update Status" with no errors. On submit, the alert displays success message: "127.0.0.1:8000 says status updated".
Task_detail.html
<div class="deliv-box edit">
<form id="status-update-form" method='POST' action='{% url "task_edit" task.pk %}'>
{% csrf_token %}
{{task_form.status}}
<input id="status-update-btn" type="submit" value="Update Status" />
</form>
</div>
...
<script type="text/javascript">
var frm = $('#status-update-form');
frm.submit(function () {
console.log("script is connected")
console.log($('#status-update-btn').val())
$.ajax({
type: frm.attr('method'),
url: frm.attr('action'),
data: frm.serialize(),
success: function (data) {
$("#deliv-box edit").html(data);
alert("status updated");
},
error: function(data) {
alert("error");
}
});
return false;
});
</script>
forms.py
class TaskForm(forms.ModelForm):
class Meta:
model = Task
fields = "__all__"
views.py
class TaskDetail(ModelFormMixin, DetailView):
template_name='task_detail.html'
model = Task
form_class = TaskForm
def get_context_data(self, **kwargs):
context = super(TaskDetail, self).get_context_data(**kwargs)
context['task_form'] = self.get_form
return context
def update(request):
if request.method=='POST':
task_id = request.POST.get('id')
task = Task.objects.get(pk = task_id)
status_obj = request.POST.get('status')
task.status = status_obj
task.save()
return JsonResponse({'status':'updated...'})
else:
return JsonResponse({'status':'not updated'})
thank you.
A solution:
In the unlikely event that someone stumbles across this question and who is, like me, just trying to figure it out all by themselves, here is what I've learned about how this works: When a user wants to update a form, Django pre-populates the form with the existing data related to that instance. A user can then alter the data and re-submit the form.
Here, I was attempting to alter just one field of the exiting instance, but as I was only calling that one field, Django was assuming not, as I had hoped, that the other fields would remain the same, but that I intended the other fields to be submitted as blank. Where the fields are required one cannot return that field as blank. Therefore, Django was not able to validate the form and so the form did not get updated.
A solution that works is to call all the fields as hidden and show just the one you want to alter. This way Django can return the unaltered data and validate the form, and you get an update button on your detail view:
<form method="POST">
{% csrf_token %}
<h4> STATUS: </h4>
{% for field in form %}
{{ field.as_hidden }}
{% endfor %}
{{form.status}}
<button type="submit" class="btn btn-success">submit</button>
</form>
You are overriding the method update which does not exist, so it is never called.
You need to subclass UpdateView instead of the DetailView and the mixin.
class TaskUpdateView(UpdateView):
template_name='task_detail.html'
model = Task
form_class = TaskForm
# you can use the line below instead of defining form_class to generate a model form automatically
# fields = ('status', )
def form_valid(self, form):
post = form.save(commit=False)
# do anything here before you commit the save
post.save()
# or instead of two lines above, just do post = form.save()
return JsonResponse({'status':'updated...'})
Here is how you would add readonly (disabled) fields to your form:
class TaskForm(forms.ModelForm):
# override the default form field definitions for readonly fields
other_field = forms.CharField(disabled=True)
another_field = forms.IntegerField(disabled=True)
class Meta:
model = Task
fields = ("status", "other_field", "another_field")
# you could also just do:
# fields = '__all__'
I am using Django 2.0 and I have a model for Articles and a model for Storylines. A storyline contains many related articles.
class Article(models.Model):
headline_text = models.CharField(max_length=255, verbose_name='Headline')
storylines = models.ManyToManyField(Storyline, verbose_name='Add to Storylines')
I have a ModelForm that will allow you to choose an article to add to the Storyline. That ModelForm class looks like this:
class StorylineAddArticleForm(forms.Form):
articleSearchBox = forms.CharField(label="Search to narrow list below:")
include_articles = [article.id for article in Article.objects.order_by('-sub_date')[:5]]
articles = forms.ModelMultipleChoiceField(queryset=Article.objects.filter(id__in=include_articles).order_by('-sub_date'))
def __init__(self, *args, **kwargs):
super(StorylineAddArticleForm, self).__init__(*args, **kwargs)
self.fields['articleSearchBox'].required = False
self.helper = FormHelper(self)
self.helper.layout = Layout(
Field('articleSearchBox'),
Field('articles'),
ButtonHolder(
Submit('submit', 'Add', css_class='button white')
)
)
So far so good, if I submit any article in the queryset, the form validates and saves as needed.
The live site will have many more articles than will be practical to display in the ModelMultipleChoice field, so I do some JQuery to allow the user to use articleSearchBox to replace the ModelMultipleChoice field. This works brilliantly and you can do a search for any article, including those not in the original queryset. Here's that:
{% block content %}
<h2>Add Article</h2>
Add an existing article to <strong>{{ storyline.headline_text }}</strong> storyline:<br>
Did you want to add a new article instead?<br>
<hr>
{% crispy form %}
{% endblock %}
{% block pagescripts %}
<script>
$(document).ready(function(){
$("#id_articleSearchBox").on('input propertychange paste', function(){
$.ajax({
url:'/webproxy/a/?q=' + $("#id_articleSearchBox").val(),
type:'get',
dataType:'html',
crossDomain:true,
success:function(data)
{
$("#id_articles").empty().append(data);
},
error: function(data) {
$("#id_articles").empty().append("<option value=\"-1\">No results</option>");
}
});
}); // end article search box
});
</script>
{% endblock %}
THE PROBLEM:
If I do a search and get an article that was not in the original queryset, the validation fails and I am told that it is not a valid choice. I need a validator that will allow any article or articles, as long as they are actually in the database.
WHAT I HAVE TRIED:
I tried creating a validator that looks like this:
def clean_article(self):
art_ID = self.cleaned_data.get('articles', False)
if(art_ID):
try:
art = Article.objects.get(pk=art_ID)
except ObjectDoesNotExist:
return None
else:
return None
# if we are here, we have an article.
return art
This produced no change in behavior. I have looked and looked for a validator that would even allow any value or just check if it exists, but I am not having a lot of luck.
Your custom validator doesn't have any effect as it will be called after the field's validation. For more information about the order validations are run in refer to the django docs.
What you can do instead is overriding said field validation by inheriting from Django's MultipleChoiceField:
from django import forms
class ArticleMultipleChoiceField(forms.MultipleChoiceField):
def validate(self, value):
pass # your custom validation
You will then of course have to use your custom ArticleMultipleChoiceField in your StorylineAddArticleForm for the articles field.
Currently using the Tango with Django book for reference. I have a bunch of products in my database in categories which are referenced with Foreign Key relationships. I seem to have an issue with returning the product view, which houses all the information about that particular product.
Example: There are two Dell laptops, one iPhone, and two iPads in the database. The product information will be returned for the iPhone, but for the iPads and the Dell laptops, it will return the message "get() returned more than one Product -- it returned 2!" which of course means that it's found two products with similar matching names. I've tried changing the name__icontains to name__iexact in the def product_view but then it stops working completely, am I missing something very obvious? As it feels like I am.
url(r'^products/(?P<category_name_url>\w+)/$', views.category_view, name='category_view'),
url(r'^products/(?P<category_name_url>\w+)/(?P<product_name_url>\w+)', views.product_view, name='product_view')
def category_view(request, category_name_url):
context = RequestContext(request)
category_list = Category.objects.order_by('name')
category_name = category_name_url.replace('_', ' ')
context_dict = {'category_name': category_name,
'categories': category_list}
try:
category = Category.objects.get(name__iexact=category_name)
product = Product.objects.filter(category=category)
context_dict['product'] = product
context_dict['category'] = category
except Category.DoesNotExist:
pass
return render_to_response('category_view.html', context_dict, context)
def product_view(request, category_name_url, product_name_url):
context = RequestContext(request)
category_list = Category.objects.order_by('name')
category_name = category_name_url.replace('_', ' ')
product_name = product_name_url.replace('-', ' ')
context_dict = {'category_name': category_name,
'product_name': product_name,
'categories': category_list}
try:
category = Category.objects.get(name__iexact=category_name)
product = Product.objects.get(name__icontains=product_name)
context_dict['category'] = category
context_dict['product'] = product
except Product.DoesNotExist:
pass
return render_to_response('product_view.html', context_dict, context)
I've tried changing the name_icontains to name_iexact in the def product_view but then it stops working completely, am I missing something very obvious?
That might be because product name that you searched does not exactly match with the one stored.
If you want to do approximation/fuzzy search you can use __icontains(), but use only one search result.
Sample code:
try:
category = Category.objects.get(name__iexact=category_name)
#use .filter()
product = Product.objects.filter(name__icontains=product_name)[0]
context_dict['category'] = category
context_dict['product'] = product
except IndexError:
#product does not exists
pass
So I'm assuming you want more than one product as you have more than one match with your query. "Get" expects to only grab one matching item. If you want both items to iterate through them, than drop the get and use filter. this will return an iterable set of objects you can parse through in your template or view.
if you have a list of iterable objects;
{% for i in product_match_list %}
{{ i.foreign_key_name.foreign_key_attribute }}
{% endfor %}
if you have one object returned by get;
{{ object_variable_name.foreign_key_name.foreign_key_attribute }}
I'm trying to extend the User model in Django using inheritance. Here's my model:
class Paciente (User):
Carteira = models.CharField(max_length=50,
verbose_name="Num Carteira Plano Saude",unique=True)
Convenio = models.ForeignKey(Operadora,'Descricao', related_name="convenio",
verbose_name="Convenio",unique=True)
DDD = models.CharField(max_length=2, verbose_name="DDD")
Telefone = models.CharField(max_length=10, verbose_name="Telefone")
And here's my view:
def paciente_register(request):
PacienteFormSet = modelformset_factory(Paciente)
if request.method == 'POST':
form = PacienteFormSet(request.POST or None,
request.FILES or None, queryset=Paciente.objects.none(),
initial=[{
'is_staff': False,
'is_active': True,
'is_superuser': False,
'date_joined': datetime.now(),
'last_login': datetime.now()
}]
) #incluir
if form.is_valid():
instance = form.save(commit=False) #pre-salva o registro
for logvalue in instance: # repoe os valores 'hidden' de log
logvalue.is_staff = False
logvalue.is_active = True
logvalue.is_superuser = False
logvalue.date_joined = datetime.now()
logvalue.last_login = datetime.now()
for reform in instance: # salva no banco
reform.save()
else:
return HttpResponseRedirect('/erro/')
else:
form = PacienteFormSet(queryset=Paciente.objects.none(),
initial=[{
'is_staff':False,
'is_active': True,
'is_superuser': False,
'date_joined': datetime.now(),
'last_login': datetime.now()
}]
) #incluir
return render_to_response('register.html', {'form': form,}, context_instance=RequestContext(request))
And, last but not least, my template:
<form enctype="multipart/form-data" method="POST" action="/paciente_register/" >{% csrf_token %}
{{ form.management_form }}
{% for formy in form.forms %}
{{ formy.username.label_tag}}:{{formy.username}}<br>
{{ formy.password.label_tag}}:{{formy.password}}<br>
{{ formy.Carteira.label_tag}}:{{formy.Carteira}}<br>
{{ formy.Convenio.label_tag}}:{{formy.Convenio}}<br>
{{ formy.DDD.label_tag}}:{{formy.DDD}}<br>
{{ formy.Telefone.label_tag}}:{{formy.Telefone}}<br>
{{formy.is_staff.as_hidden}}
{{formy.is_active.as_hidden}}
{{formy.is_superuser.as_hidden}}
{{formy.date_joined.as_hidden}}
{{formy.last_login.as_hidden}}
{% endfor %}
<input type="submit" name="submit" value="Salvar" />
</form>
The user is supposed to register himself, but he will only have access to edit some of the fields, because the others I am setting inside the view and in the template, I am hiding them.
But the thing is that my form is not validating. I did a lot of research, but just a few examples over the internet use inheritance to extend User model. And this ones, does not show how would be the view that makes the registration of the user inside the application.
Any help would be very appreciated! :)
The problem was on the view, after all. I was forcing the fields "date_joined" and "last_login" to receive datetime.now() because I was following the Django admin template. Sadly, this wasn't correct and everytime I tried to add a user, it was jumping to the error template, which means that the form wasn't filled properly. The solution was to make those fields receive date.today() and now it works fine.
I think this model inheritance is still not working very good (Python 2.7 and Django 1.3). When you use it in your models, be sure of what kind of field Django is creating inside your database, and this will save you a lot of trouble.
In general, I think the model inheritance is working fine and without significant issues.
With regard to the User model, I do not have too much experience, but maybe your issues result from the fact that you are not doing it as proposed by Django ?
Just in case that your are intersted, some more interesting posts: h
Extending the User model with custom fields in Django
http://www.b-list.org/weblog/2006/jun/06/django-tips-extending-user-model/,http://www.turnkeylinux.org/blog/django-profile