Generate QR Code to URL with variable (page/pk_ID)

Question:

I am trying to generate a QR code that is unique to the page_id.

The aim is to send a user that is not request.user to a specific page (loyalty_card/UserProfile_ID).

As an example:

  1. site/loyaltycard/UserProfile_1 – would have qr code leading to site/pageID_1
  2. site/loyaltycard/pageID_2 – would have qr code leading to site/pageID_2

here is where I am at.

from io import BytesIO
from qrcode.image.svg import SvgImage

@login_required
def venue_loyalty_card(request, userprofile_id):

    profile = UserProfile.objects.filter(user=userprofile_id)
    itemised_loyalty_cards = Itemised_Loyatly_Card.objects.filter(user=userprofile_id)
    
    factory = qrcode.image.svg.SvgImage
    stream = BytesIO()
    qrcode_url = "....com/account/" + str(userprofile_id) + "/"
    qrcode_img = qrcode.make(qrcode_url, image_factory=factory, box_size=10)
    qrcode_img.save(stream)
 
    
    return render(request,"main/account/venue_loyalty_card.html", {'itemised_loyalty_cards':itemised_loyalty_cards, 'profile':profile,'qrcode_url':qrcode_url,'qrcode_img':qrcode_img})

template

{% block content %}

</br></br>
Your Loyalty Cards</br>
</br>

<img style="width: 100%" src="{{qrcode_img|safe}}">
{%for userprofile in profile%}


{%endfor%}
{%for itemised_loyatly_card in itemised_loyalty_cards %}</br>

    {% if request.user.id == itemised_loyatly_card.user.id %} 
    Total Points: {{itemised_loyatly_card.sum}}</br>
    User : {{itemised_loyatly_card.user.id}}</br>
    Venue :{{itemised_loyatly_card.venue}}</br>
    Add points here: {{itemised_loyatly_card.points}}</br>
    {%else%}
    {%endif%}
{%endfor%}
{%endblock%}

url

path('loyalty_card/<userprofile_id>', views.venue_loyalty_card,name="venue-loyalty-card"),

Current error message on console: (edit following Rudra’s demand)

System check identified no issues (0 silenced).
January 05, 2023 - 11:55:32
Django version 4.0.6, using settings 'mysite.settings.dev'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
[05/Jan/2023 11:55:35] "GET /loyalty_card/17 HTTP/1.1" 200 11017
Internal Server Error: /loyalty_card/<qrcode.image.svg.SvgImage object at 0x00000227BFB77EE0>
Traceback (most recent call last):
  File "C:UsersCeXVirtuallibsite-packagesdjangodbmodelsfields__init__.py", line 1988, in get_prep_value
    return int(value)
ValueError: invalid literal for int() with base 10: '<qrcode.image.svg.SvgImage object at 0x00000227BFB77EE0>'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:UsersCeXVirtuallibsite-packagesdjangocorehandlersexception.py", line 55, in inner
    response = get_response(request)
  File "C:UsersCeXVirtuallibsite-packagesdjangocorehandlersbase.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "C:UsersCeXVirtuallibsite-packagesdjangocontribauthdecorators.py", line 23, in _wrapped_view
    return view_func(request, *args, **kwargs)
  File "C:UsersCeXDevmysiteMyAppmainviews.py", line 730, in venue_loyalty_card
    profile = UserProfile.objects.filter(user=userprofile_id)
  File "C:UsersCeXVirtuallibsite-packagesdjangodbmodelsmanager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "C:UsersCeXVirtuallibsite-packagesdjangodbmodelsquery.py", line 1071, in filter
    return self._filter_or_exclude(False, args, kwargs)
  File "C:UsersCeXVirtuallibsite-packagesdjangodbmodelsquery.py", line 1089, in _filter_or_exclude
    clone._filter_or_exclude_inplace(negate, args, kwargs)
  File "C:UsersCeXVirtuallibsite-packagesdjangodbmodelsquery.py", line 1096, in _filter_or_exclude_inplace
    self._query.add_q(Q(*args, **kwargs))
  File "C:UsersCeXVirtuallibsite-packagesdjangodbmodelssqlquery.py", line 1502, in add_q
    clause, _ = self._add_q(q_object, self.used_aliases)
  File "C:UsersCeXVirtuallibsite-packagesdjangodbmodelssqlquery.py", line 1532, in _add_q
    child_clause, needed_inner = self.build_filter(
  File "C:UsersCeXVirtuallibsite-packagesdjangodbmodelssqlquery.py", line 1448, in build_filter
    condition = self.build_lookup(lookups, col, value)
  File "C:UsersCeXVirtuallibsite-packagesdjangodbmodelssqlquery.py", line 1273, in build_lookup
    lookup = lookup_class(lhs, rhs)
  File "C:UsersCeXVirtuallibsite-packagesdjangodbmodelslookups.py", line 27, in __init__
    self.rhs = self.get_prep_lookup()
  File "C:UsersCeXVirtuallibsite-packagesdjangodbmodelsfieldsrelated_lookups.py", line 154, in get_prep_lookup
    self.rhs = target_field.get_prep_value(self.rhs)
  File "C:UsersCeXVirtuallibsite-packagesdjangodbmodelsfields__init__.py", line 1990, in get_prep_value
    raise e.__class__(
ValueError: Field 'id' expected a number but got '<qrcode.image.svg.SvgImage object at 0x00000227BFB77EE0>'.
[05/Jan/2023 11:55:35] "GET /loyalty_card/%3Cqrcode.image.svg.SvgImage%20object%20at%200x00000227BFB77EE0%3E HTTP/1.1" 500 134352
Asked By: PhilM

||

Answers:

I think it is related to trying to make the image object safe in template. Instead, you can get the binary data value from the image object (I assume you are using PIL/Pillow for install qrcode library):

# view
qrcode_img.save(stream)
img_url =  qrcode_img.to_string()

return render(request,"..", {...,'qrcode_img':img_url })

# template
{{ qrcode_img | safe }} // not inside img tag

Unrelated to the original question, but you can consider further improvement on your code like removing loops from template. To do that, you can update the view and template like this:

# view
profile = UserProfile.objects.get(user=userprofile_id)
itemised_loyalty_card = Itemised_Loyatly_Card.objects.get(user=userprofile_id)

# template
{{ profile }}
{{ if profile.user == request.user }}
    {{ itemised_loyatly_cards.sum }} // you can rename the context variable as well
{{ endif }}
Answered By: ruddra