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
- Using RelatedFieldWidgetWrapper:
I attempted to wrap the
color
field widget usingRelatedFieldWidgetWrapper
inProductAdminForm
:
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
)
- 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.
- Checking Admin Registration:
The
Color
model is properly registered in the admin:
@admin.register(Color)
class ColorAdmin(admin.ModelAdmin):
list_display = ['name', 'code']
- 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
- Display the "plus" icon in the
color
field on the customadd-product.html
page. - 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'