AttributeError: 'str' object has no attribute 'is_registered' in Django Custom Add Product Page

Title: AttributeError: 'str' object has no attribute 'is_registered' in Django Custom Add Product Page


Problem Statement: I am creating a custom page in Django to allow users (staff members) to add a product. The product is defined in the Product model, which includes a ManyToManyField for Color. While the product creation works fine in the admin panel (with the ability to add new colors using the "plus" icon in the color field), this functionality does not work in my custom page.

When attempting to wrap the widget for the color field using RelatedFieldWidgetWrapper, I encounter the following error:

AttributeError at /useradmin/add_product/
'str' object has no attribute 'is_registered'

Below are the relevant code snippets and configurations. I’d appreciate any help identifying the issue and achieving the desired functionality.


Models

Product Model

from django.db import models
from taggit.managers import TaggableManager
from shortuuidfield import ShortUUIDField
from ckeditor_uploader.fields import RichTextUploadingField
from django.utils.safestring import mark_safe

class Product(models.Model):
    pid = ShortUUIDField(length=10, max_length=100, prefix="prd", alphabet="abcdef")
    user = models.ForeignKey('CustomUser', on_delete=models.SET_NULL, null=True)
    viewers = models.ManyToManyField('CustomUser', related_name="viewed_products", blank=True)
    cagtegory = models.ForeignKey('Category', on_delete=models.SET_NULL, null=True, related_name="category")
    subcategory = models.ForeignKey('SubCategory', on_delete=models.SET_NULL, null=True, blank=True, related_name="subcategory")
    vendor = models.ForeignKey('Vendor', on_delete=models.SET_NULL, null=True, related_name="product")
    main_product_color = models.ManyToManyField('Color_main', blank=True)
    color = models.ManyToManyField('Color', blank=True)
    size = models.ManyToManyField('Size', blank=True)
    title = models.CharField(max_length=100, default="Apple")
    image = models.ImageField(upload_to='uploads/products', default="product.jpg")
    hover_image = models.ImageField(upload_to='uploads/products', default="product.jpg")
    description = RichTextUploadingField(null=True, blank=True, default="This is a product")
    price = models.DecimalField(max_digits=10, decimal_places=2, default=1.99)
    old_price = models.DecimalField(max_digits=10, decimal_places=2, default=2.99)
    specifications = RichTextUploadingField(null=True, blank=True)
    tags = TaggableManager(blank=True)
    return_days = models.PositiveIntegerField(default=7)
    product_status = models.CharField(choices=[('In_review', 'In Review'), ('Approved', 'Approved')], max_length=1000, default="In_review")
    yt_link = models.CharField(max_length=10000, blank=True, null=True)
    status = models.BooleanField(default=True)
    in_stock = models.BooleanField(default=True)
    featured = models.BooleanField(default=False)
    digital = models.BooleanField(default=False)
    best_selling = models.BooleanField(default=False)
    our_choice = models.BooleanField(default=False)
    non_returnable = models.BooleanField(default=False)
    sku = ShortUUIDField(length=10, max_length=100, prefix="sku", alphabet="abcdef")
    date = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(null=True, blank=True)

    class Meta:
        verbose_name_plural = "Products"

    def product_image(self):
        return mark_safe('<img src="%s" width="50" height="50"/>' % (self.image.url))

    def __str__(self):
        return self.title

Color Model

class Color(models.Model):
    coid = ShortUUIDField(length=10, max_length=100, prefix="col", alphabet="abcdefgh")
    name = models.CharField(max_length=20)
    code = models.CharField(max_length=7, default="#FF0000")
    product_varients = models.ManyToManyField('Product', related_name='color_variants', blank=True)
    image = models.ImageField(upload_to='uploads/colors', default="color.jpg")

    class Meta:
        verbose_name_plural = "Colors"

    def __str__(self):
        return self.name

Admin Configuration

ProductAdminForm

from django import forms
from core.models import Product

class ProductAdminForm(forms.ModelForm):
    class Meta:
        model = Product
        fields = '__all__'

ProductAdmin

from django.contrib import admin
from core.models import Product

class ProductAdmin(admin.ModelAdmin):
    list_display = ['user', 'title', 'product_image', 'price', 'featured', 'product_status', 'pid']
    filter_horizontal = ['color', 'size']
    form = ProductAdminForm

admin.site.register(Product, ProductAdmin)

Custom Add Product View

from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required, user_passes_test
from core.forms import ProductAdminForm

@login_required
@user_passes_test(lambda user: user.is_staff)
def add_product(request):
    if request.method == "POST":
        form = ProductAdminForm(request.POST, request.FILES)
        if form.is_valid():
            new_product = form.save(commit=False)
            new_product.user = request.user
            new_product.save()
            form.save_m2m()
            return redirect("useradmin:vendordashboard")
        else:
            print(form.errors)
    else:
        form = ProductAdminForm()

    return render(request, "useradmin/add-product.html", {"form": form})

Error Details

Error:

AttributeError at /useradmin/add_product/
'str' object has no attribute 'is_registered'

Traceback: The error occurs when the custom page is loaded. The issue seems to arise when the RelatedFieldWidgetWrapper is used with the color field.


What I Have Tried

  1. Using RelatedFieldWidgetWrapper: I attempted to wrap the color field widget using RelatedFieldWidgetWrapper in ProductAdminForm:
from django.contrib.admin.widgets import RelatedFieldWidgetWrapper
from django.urls import reverse

class ProductAdminForm(forms.ModelForm):
    class Meta:
        model = Product
        fields = '__all__'

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if 'color' in self.fields:
            rel = self._meta.model._meta.get_field('color').remote_field
            self.fields['color'].widget = RelatedFieldWidgetWrapper(
                self.fields['color'].widget,
                rel,
                reverse('admin:core_color_add')  # Admin add URL
            )
  1. Verifying the Reverse URL: I verified the URL for adding a Color object in the admin:
from django.urls import reverse
print(reverse('admin:core_color_add'))  # Outputs: '/admin/core/color/add/'

The URL resolves correctly.

  1. Checking Admin Registration: The Color model is properly registered in the admin:
@admin.register(Color)
class ColorAdmin(admin.ModelAdmin):
    list_display = ['name', 'code']
  1. Including Admin Media in the Template: I ensured the admin JavaScript and CSS files are loaded in my custom page:
{% load static %}
<link rel="stylesheet" href="{% static 'admin/css/widgets.css' %}">
<script src="{% static 'admin/js/core.js' %}"></script>
<script src="{% static 'admin/js/admin/RelatedObjectLookup.js' %}"></script>

Desired Outcome

  1. Display the "plus" icon in the color field on the custom add-product.html page.
  2. Allow staff users to add new colors via the "plus" icon without encountering errors.

Question

What is causing the 'str' object has no attribute 'is_registered' error, and how can I resolve it to achieve the desired functionality?


Full Trackback error

Environment:


Request Method: GET
Request URL: http://127.0.0.1:8000/useradmin/add_product/

Django Version: 5.1.3
Python Version: 3.12.5
Installed Applications:
['jazzmin',
 'colorfield',
 'core.apps.CoreConfig',
 'django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django.contrib.humanize',
 'taggit',
 'ckeditor',
 'ckeditor_uploader',
 'tailwind',
 'channels',
 'twilio',
 'django_celery_beat',
 'paypal.standard.ipn',
 'googleapiclient',
 'userauths',
 'others',
 'useradmin',
 'vendorpannel',
 'deladmin',
 'staffdata',
 'videoshareing',
 'notification_app',
 'customercare']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']



Traceback (most recent call last):
  File "C:\Users\sagar\AppData\Local\Programs\Python\Python312\Lib\site-packages\django\core\handlers\exception.py", line 55, in inner
    response = get_response(request)
               ^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\sagar\AppData\Local\Programs\Python\Python312\Lib\site-packages\django\core\handlers\base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\sagar\AppData\Local\Programs\Python\Python312\Lib\site-packages\django\contrib\auth\decorators.py", line 60, in _view_wrapper
    return view_func(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\sagar\AppData\Local\Programs\Python\Python312\Lib\site-packages\django\contrib\auth\decorators.py", line 60, in _view_wrapper
    return view_func(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\sagar\OneDrive\Desktop\django ecom web\ecomprj\useradmin\views.py", line 120, in add_product
    form = ProductAdminForm()
           ^^^^^^^^^^^^^^^^^^
  File "C:\Users\sagar\OneDrive\Desktop\django ecom web\ecomprj\core\admin.py", line 65, in __init__
    self.fields['color'].widget = RelatedFieldWidgetWrapper(
                                  
  File "C:\Users\sagar\AppData\Local\Programs\Python\Python312\Lib\site-packages\django\contrib\admin\widgets.py", line 271, in __init__
    can_add_related = admin_site.is_registered(rel.model)
                      ^^^^^^^^^^^^^^^^^^^^^^^^

Exception Type: AttributeError at /useradmin/add_product/
Exception Value: 'str' object has no attribute 'is_registered'
Back to Top