Aishwary Shukla
Aishwary Shukla

Reputation: 460

Converting from a Model Type to string in python django

Following is a snapshot of one of my models in django application:

class Request(models.Model):
    device_type                     = models.ForeignKey(DeviceType,to_field='device_type')
    requested_by                    = models.ForeignKey(User,to_field='username')
    urgency                         = models.ForeignKey(RequestUrgency,to_field='request_urgency')
    request_must_be_satisfied_by    = models.DateField(null=True)
    reason                          = models.TextField()
    status                          = models.ForeignKey(ResuestStatus,to_field='request_status',default="PENDING")
    request_date                    = models.DateField(default=datetime.now)

def __unicode__(self):
    return self.device_type

def __str__(self):
    return self.device_type

Code inside the views.py file:

def request_form(request):
    if request.method == "POST":
        print("Inside out if")
        form = RequestForm(request.POST)
        print("request form: ", form)
        print("request fields ", form.fields)
        print("errors: ",form.errors.as_data())
        if form.is_valid():
        print("errors: ",form.errors.as_data())
        if form.is_valid():
            cleaned_data = form.cleaned_data

            post = form.save(commit = False)
            post.requested_by_id = request.user
            post.save()

            userdata = User.objects.get(username = request.user.username)
            useremail = userdata.email
            email_body_text = "Hi "+request.user.username+","+"\n"+"Your requested a repair for the following:"+"\n"\
                        +"Device Type: "+cleaned_data["device_type"]+"\n"\
                        +"Urgency: "+cleaned_data["urgency"]+"\n"\
                        +"Request must be satisfied by: "+cleaned_data["request_must_be_satisfied_by"]+"\n"\
                        +"Reason for new device: "+cleaned_data["reason"]+"\n"\
                        +"We will try to complete your request at the earliest. In case of any concerns contact the controller of operations."

            send_mail(email_subject,email_body_text,config.sender_email_id,[useremail],fail_silently=False)


        return redirect("NewRequest")

    else:
        print("Inside else")
        form = RequestForm(initial={'requested_by':request.user})
        Tp = DeviceType.objects.all()
        Tp = Tp.annotate(text=F('device_type')).values_list('text', flat=True)
        print("Tp request form: ", Tp)
        Ur = RequestUrgency.objects.all()
        Ur = Ur.annotate(text=F('request_urgency')).values_list('text', flat=True)
        form.fields["device_type"] = forms.ModelChoiceField(queryset=Tp, empty_label=None)
        form.fields["urgency"] = forms.ModelChoiceField(queryset=Ur, empty_label=None)
        return render(request, "Form_template.html", {"form": form, \
                                                  "name": "Device Request Form"})

Now, I have a function in my views.py that validates the data that is submitted through the django rendered form. Now, I have a situation, I want to print the data sent through the form by concatinating it with a particular string. Whenever I got to do so. I get the following error:

TypeError: coercing to Unicode: need string or buffer, DeviceType found 

How should I overcome this problem?

Upvotes: 0

Views: 5877

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476659

The problem is that you add strings and non-strings together when you construct the email_body_text. Python does not understand what a string together with a device_type is supposed to mean. This is not strange, adding a string and a number has the same problems:

>>> u"abc" + 3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: coercing to Unicode: need string or buffer, int found

As you see, the message is exactly the same, except for the fact that here we use an int instead of a DeviceType.

You better solve this by performing string formatting. This is not only more type safe (since it will call unicode(..) and str(..) behind the curtains, but is also more elegant.

But there are other problems with the view as well: for example you use cleaned_data instead of the Request object you constructed in the form, which make things easier, more elegant and readable:

def request_form(request):
    if request.method == "POST":
        form = RequestForm(request.POST)
        if form.is_valid():
            post = form.save(commit = False)
            post.requested_by_id = request.user
            post.save()

            user = request.user
            useremail = user.email
            email_body_text = (
                u"Hi {},"
                "\nYour requested a repair for the following:"
                "\nDevice Type: {}"
                "\nUrgency: {}"
                "\nRequest must be satisfied by: {}"
                "\nReason for new device: {}"
                "\nWe will try to complete your request at the earliest."
                "In case of any concerns contact the controller of operations."
            ).format(
                user.username,
                post.device_type,
                post.urgency,
                post.request_must_be_satisfied_by,
                post.reason,
            )

            send_mail(email_subject,email_body_text,config.sender_email_id,[useremail],fail_silently=False)
            return redirect("NewRequest")
    else:
        form = RequestForm(initial={'requested_by':request.user})
        Tp = DeviceType.objects.all()
        Tp = Tp.annotate(text=F('device_type')).values_list('text', flat=True)
        print("Tp request form: ", Tp)
        Ur = RequestUrgency.objects.all()
        Ur = Ur.annotate(text=F('request_urgency')).values_list('text', flat=True)
        form.fields["device_type"] = forms.ModelChoiceField(queryset=Tp, empty_label=None)
        form.fields["urgency"] = forms.ModelChoiceField(queryset=Ur, empty_label=None)
    return render(request, "Form_template.html", {"form": form, "name": "Device Request Form"})

Note; I advice you to migrate to Python-3.x, since Python-2.x will no longer be supported within two years: https://pythonclock.org/

Upvotes: 2

Related Questions