django-bootstrap3 Parameter "field" should contain a valid Django BoundField? - python

I am using django-bootstrap3 to render my forms on the template and i have been struggling to find what is causing the error Parameter "field" should contain a valid Django BoundField when i try to load the page with the form on it. I have attached my code and error below. can someone please point for me what i'm doing wrong?
forms.py
class OrderForm(forms.Form):
first_name = forms.CharField(max_length=50)
last_name = forms.CharField(max_length=50)
email = forms. EmailField(max_length=50)
institution_name = forms.CharField(max_length=150)
phone = forms.IntegerField()
address = forms.CharField(max_length=100)
city = forms.CharField(max_length=50)
item = forms.CharField(max_length=100)
serial_number = forms.CharField(max_length=50)
problem = forms.CharField(widget=forms.Textarea(attrs—Crows':10,'cols':18,'style':'resize:none', [placeholder':'Please define your problem here'l),label='Problem description')
[placeholder':'Please define your problem here'l),label='Problem description')
views.py
def Orderview(request):
if request.method == 'Post':
order_form = OrderForm(request.POST)
if order_form.is_valid():
cd = order form.cleaned data
subject = '{} repair order from {}'.format(cd['item'],cd['institution_name'])
from_email = cd['email']
to = [settings.EMAIL_HOST_USER,]
ctx = {
'first_name':cd['first_name'],
'last_name':cd['last_name'],
'email':cd['email'],
'institution_name':cd['institution_name'],
'phone':cd['phone'],
'address':cd['address'],
'city':cd['city'],
'item':cd['item'],
'serial_number.:cd['serial_number'],
'problem':cd['problem'],
}
message = get_template('electroapp/email/order.html').render(Context(ctx))
msg = EmailMessage(subject,message,to=to,from_email=from_email)
msg.content_subtype='html'
msg.send()
messages.success(request,' Your Repair order has been sent',)
return redirect('electroapp:repair_order')
else:
order_form = OrderForm()
return render(request,'electroapp/orderform.html',{'Order_form':order_form})
template
browser error
console logs

This could be because some fields may be missing.Take a look at this
You could do something like this to see what fields are available:
<form role="form" method="post">
{% csrf_token %}
{% bootstrap_form order_form %}
{% buttons submit='OK' reset="Cancel" %}{% endbuttons %}
</form>
and then try to figure out why you are having missing fields.

Parameter "field" should contain a valid Django BoundField
Why can't they just tell us which actual field? Well, here's how I solved it.
A little debugging and you'll find this is thrown within renderers.py:
class FieldRenderer(BaseRenderer):
"""Default field renderer."""
# These widgets will not be wrapped in a form-control class
WIDGETS_NO_FORM_CONTROL = (CheckboxInput, RadioSelect, CheckboxSelectMultiple, FileInput)
def __init__(self, field, *args, **kwargs):
if not isinstance(field, BoundField):
raise BootstrapError('Parameter "field" should contain a valid Django BoundField.')
self.field = field
super().__init__(*args, **kwargs) ...
The message is not helpful, but can be fixed in your dev/test environment.
WARNING: The following will void your warranty! :)
Go up a few steps in the render chain in library.py (for example ~/.virtualenvs/your_env/lib/python3.8/site/packages/django/template/library.py)
and find SimpleNode.
class SimpleNode(TagHelperNode):
def __init__(self, func, takes_context, args, kwargs, target_var):
super().__init__(func, takes_context, args, kwargs)
self.target_var = target_var
def render(self, context):
resolved_args, resolved_kwargs = self.get_resolved_arguments(context)
output = self.func(*resolved_args, **resolved_kwargs)
if self.target_var is not None:
context[self.target_var] = output
return ''
if context.autoescape:
output = conditional_escape(output)
return output
After copying the original file to a backup, change it as follows. We are wrapping the line
output = self.func(*resolved_args, **resolved_kwargs)
with a try/except. Here's the result:
class SimpleNode(TagHelperNode):
def __init__(self, func, takes_context, args, kwargs, target_var):
super().__init__(func, takes_context, args, kwargs)
self.target_var = target_var
def render(self, context):
resolved_args, resolved_kwargs = self.get_resolved_arguments(context)
###
from bootstrap3.exceptions import BootstrapError
try:
output = self.func(*resolved_args, **resolved_kwargs)
except BootstrapError as b:
raise BootstrapError(str(b).replace('"field"', self.args[0].token)) from b
###
if self.target_var is not None:
context[self.target_var] = output
return ''
if context.autoescape:
output = conditional_escape(output)
return output
Within the SimpleNode class we have access to the name of the field that couldn't be rendered. So we intercept the exception there and re-throw it with the useful tidbit injected. Voila, you will now get an exception report that tells you the actual problem field.
Cheers.

Related

How can I pass a model id from the url to a class based view?

I have a class-based view:
class Create(View):
note_id = None
http_method_names = ['post', 'patch']
default_title = "You fool! This was left empty"
default_body = "Why did you leave this blank :("
def dispatch(self, *args, **kwargs):
method = self.request.POST.get('_method', '').lower()
print('method = ', method)
if method == 'patch':
return self.patch(*args, **kwargs)
elif method == 'post':
self.post(*args, **kwargs)
return super(Create, self).dispatch(*args, **kwargs)
def post(self, note_id):
date = datetime.date.today()
title = self.request.POST.get('title', '')
body = self.request.POST.get('note', '')
# check for blank attributes
if title == "":
title = Create.default_title
if body == "":
body = Create.default_body
note = Note(note_title=title, note_body=body, publish_date=date, edit_date=None)
note.save()
return HttpResponseRedirect(reverse('notes:note'))
def patch(self, note_id):
note = Note.objects.get(id=note_id)
title = self.request.POST.get('title', '')
body = self.request.POST.get('note', '')
# if something changed
if title != note.note_title or body != note.note_body:
# check for blank attributes
if title == "":
title = Create.default_title
if body == "":
body = Create.default_body
note.note_title = title
note.note_body = body
note.edit_date = datetime.date.today()
note.save()
return HttpResponseRedirect(reverse('notes:note'))
and in url.py I have
urlpatterns = [
path('<int:note_id>/create/', views.Create.as_view(), name='create'),
path('<int:note_id>/edit/', views.Create.as_view(), name='edit')
]
Previously, with function-based views the note_id would just be passed to the function automatically. I can not figure out the equivalent of this in class based views. I've tried explictiely passing note_id to each function, but that did not work. I tried included Create.as_view(note_id=note_id) in my url.py, but to no avail.
Currently, running this code I get:
post() got multiple values for argument 'note_id'
As mentioned in the comment above, you need to access these values through self.kwargs. e.g:
class Create(View):
note_id = None # Delete this line
...
# delete the dispatch method - no need to overwrite this.
# Don't include note_id as an argument, but request should be an argument
def post(self, request):
note_id = self.kwargs['note_id']
....
def put(self, request): # Likewise here
note_id = self.kwargs['note_id']
....
It doesn't look like you need to write a custom dispatch method. If all you are doing is calling the appropriate method, then the dispatch method that comes for free with View is just fine :)

Follow system returning User matching query does not exist error

I have been working on a follow system on django which needs to have the same functionality as instagram's one; meaning that a user can follow and be followed by other other users and in a user's profile there is a follower count that displays the number of followers a user has, together with a following count that displays the number of people a user is following.
So everything was working good and there was one missing functionality to complete the follow system and it was the follower count. To get this done, I created a signals.py file, but as soon as I did that The follow/unfollow button was not working due to a internal server 500 error, so after some investigation I realized that the 500 error was happening because there is this error DoesNotExist at /accounts/follow/username User matching query does not exist. Why is it poping that error, can it be solved?
signals.py
#receiver(m2m_changed, sender = Following.followed.through) # which list is changed
def add_follower(sender, instance, action, reverse, pk_set, **kwargs):
followed_users = [] # list of users main (logged ) user have followed
logged_user = User.objects.get(username = instance) # user who followed other users
for i in pk_set:
user = User.objects.get(pk = i)
following_obj = Following.objects.get(user = user)
followed_users.append(following_obj)
if action == "pre_add":
for i in followed_users:
i.follower.add(logged_user)
i.save()
if action == "pre_remove":
for i in followed_users:
i.follower.remove(logged_user)
i.save()
models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
connection = models.CharField(max_length = 100, blank=True)
follower = models.IntegerField(default=0)
following = models.IntegerField(default=0)
def __str__(self):
return f'{self.user.username} Profile'
class Following(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
followed = models.ManyToManyField(User, related_name="followed")
follower = models.ManyToManyField(User, related_name="follower")
#classmethod
def follow(cls, user, another_account):
obj, create = cls.objects.get_or_create(user = user)
obj.followed.add(another_account)
print("followed")
#classmethod
def unfollow(cls, user, another_account):
obj, create = cls.objects.get_or_create(user = user)
obj.followed.remove(another_account)
print("unfollowed")
def __str__(self):
return f'{self.user.username} Profile'
views.py
def follow(request, username):
main_user = request.user
to_follow = User.objects.get(username=username)
following = Following.objects.filter(user = main_user, followed = to_follow)
is_following = True if following else False
if is_following:
Following.unfollow(main_user, to_follow)
is_following = False
else:
Following.follow(main_user, to_follow)
is_following = True
resp = {
'following': is_following,
}
response = json.dumps(resp)
return HttpResponse(response, content_type="application/json")
def profile(request, username):
user = User.objects.filter(username=username)
if user:
post_owner = get_object_or_404(User, username=username)
user = user[0]
is_following = Following.objects.filter(user=request.user, followed=user)
following_obj = Following.objects.get(user=user)
follower = following_obj.follower.count()
following = following_obj.followed.count()
args1 = {
'user_obj':user,
'post_owner': post_owner,
'follower': follower,
'following': following,
'connection': is_following,
}
else: return HttpResponse("NO SUCH USER")
return render(request, 'profile.html', args1)
profile.html
<head>
<link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/npm/slick-carousel#1.8.1/slick/slick.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script type="text/javascript" src="//cdn.jsdelivr.net/npm/slick-carousel#1.8.1/slick/slick.min.js"></script>
</head>
<body>
{% if connection %}
<a type="button" class="button-caballo" id="follow" role="button" href="{% url 'follow' user_obj.username %}">Unfollow</a>
{% elif not connection %}
<a type="button" class="button-caballo" id="follow" role="button" href="{% url 'follow' user_obj.username %}">Follow</a>
{% endif %}
<script type="text/javascript">
$("#follow").click(function(e){
e.preventDefault();
var href = this.href;
$.ajax({
url : href,
success : function(response){
if(response["following"]){
$("#follow").html("Unfollow");
}
else{
$("#follow").html("Follow");
}
}
})
})
</script>
</body>
traceback
Traceback (most recent call last):
File "C:\Users\USER\Envs\startup\lib\site-packages\django\core\handlers\exception.py", line 34, in inner
response = get_response(request)
File "C:\Users\USER\Envs\startup\lib\site-packages\django\core\handlers\base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "C:\Users\USER\Envs\startup\lib\site-packages\django\core\handlers\base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\USER\startup\gstartup\accounts\views.py", line 110, in follow
Following.unfollow(main_user, to_follow)
File "C:\Users\USER\startup\gstartup\accounts\models.py", line 43, in unfollow
obj.followed.remove(another_account)
File "C:\Users\USER\Envs\startup\lib\site-packages\django\db\models\fields\related_descriptors.py", line 961, in remove
self._remove_items(self.source_field_name, self.target_field_name, *objs)
File "C:\Users\USER\Envs\startup\lib\site-packages\django\db\models\fields\related_descriptors.py", line 1179, in _remove_items
signals.m2m_changed.send(
File "C:\Users\USER\Envs\startup\lib\site-packages\django\dispatch\dispatcher.py", line 173, in send
return [
File "C:\Users\USER\Envs\startup\lib\site-packages\django\dispatch\dispatcher.py", line 174, in <listcomp>
(receiver, receiver(signal=self, sender=sender, **named))
File "C:\Users\USER\startup\gstartup\accounts\signals.py", line 16, in add_follower
logged_user = User.objects.get(username = instance) # user who followed other users
File "C:\Users\USER\Envs\startup\lib\site-packages\django\db\models\manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "C:\Users\USER\Envs\startup\lib\site-packages\django\db\models\query.py", line 415, in get
raise self.model.DoesNotExist(
django.contrib.auth.models.User.DoesNotExist: User matching query does not exist.
If you have any questions or need to see more code please let meknow in the comments;)
I am a bit confuse about the sender, but I am pretty sure your instance variable is an object of User class and for filtering you should use
logged_user = User.objects.get(username = instance.username)
note1: If instance is an User instance, I don't see why the query is needed.
note2: If it's not an User instance, check it's class and use field name instead of instance.
DoesNotExist Error
The issue you seem to be encountering is here:
to_follow = User.objects.get(username=username) located in your views.py.
This will raise a DoesNotExist error and respond with a 500 if object is not found. Consider using get_object_or_404 instead.
Consider removing the signal. Count method as detailed in the example below should be efficient enough. If any more is necessary consider higher level caching solution instead.
Idiosyncrasies
Consider using a custom User
model
instead of Profiles.
Consider using manager
methods
instead of class methods.
Consider using class based
views
with mixins and separating business logic into contextual methods to
make unit testing and debugging easier.
Consider writing unit
tests
for each of your model and view methods to more easily identify bugs
when they happen.
Your models.py should be refactored to the something resembling the following to reduce complexity and increase data integrity:
class UserManager(models.Manager):
def follow(user, user_to_follow):
obj, created = self.objects.get_or_create(user = user)
return self.profile.following.add(user, user_to_follow)
def unfollow(self, user)
obj, created = self.objects.get_or_create(user = user)
return self.following.remove(profile, user_to_unfollow)
class User(AbstractUser):
connection = models.CharField(max_length=100, blank=True)
following = models.ManyToManyField(self, "following")
followers = models.ManyToManyField(self, "followers")
objects = UserManager()
def follower_count(self):
return User.objects.filter(following=self).count()
def following_count(self):
return User.objects.filter(followers=self).count()
def __str__(self):
return f'{self.user.username} Profile'
# Profile.objects.follow(user, user_to_follow)
# Profile.objects.unfollow(user, user_to_follow)
# profile.follower_count()
# profile.following_count()
References
get object or 404
Custom User Models: https://docs.djangoproject.com/en/3.0/topics/auth/customizing/#using-a-custom-user-model-when-starting-a-project
Manager Methods: https://docs.djangoproject.com/en/3.0/topics/db/managers/#adding-extra-manager-methods
Unit Tests: https://docs.djangoproject.com/en/dev/topics/testing/overview/
Unit Test for View example: https://docs.djangoproject.com/en/3.0/intro/tutorial05/#testing-the-detailview
DetailView code example for domain logic separation: https://github.com/django/django/blob/b9cf764be62e77b4777b3a75ec256f6209a57671/django/views/generic/detail.py#L8-L100
Class based views: https://docs.djangoproject.com/en/3.0/topics/class-based-views/

After importing variable from view.py into. No dropdown appearing in forms

I am using Django forms in in forms I need a variable from views.py named 'layer_id'. So I get it like
self.form = labelModelForm(layer_id=self.layer.id)
and used in forms.py like
class labelModelForm(forms.ModelForm):
model = Labels_tool_
def __init__(self, *args , **kwargs):
layer_id = kwargs['layer_id']
apn= forms.ModelChoiceField(queryset=Field.objects.filter(layer=layer_id).values_list('name', flat=True) ,empty_label="(Choose field)")
So now when I run program no dropdown list appear. Where I am wrong ? As layer_id I am getting is correct in form in view.py
My View.py file is
def ImportLabelView(self):
urlItems =self.request.path.split('/')
i = urlItems.index('layers')
self.form = labelModelForm(layer_id=self.layer.id)
if self.request.method == 'POST':
self.layer = Layer.objects.filter(id=urlItems[i + 1],map=self.map.id).first()
layerid= self.layer.id
labmapid=self.map.id
OwnerName = self.request.POST.get('owner_name')
MailingAddrOne = self.request.POST.get('mailing_addr_One')
mailingaddrTwo = self.request.POST.get('mailing_addr_Two')
ApN = self.request.POST.get('apn')
situsaddrTwo = self.request.POST.get('situs_addr_Two')
situsaddrOne = self.request.POST.get('situs_addr_One')
if Labels_tool_.objects.filter(map_id_labels=labmapid ,layer_id_labels=layerid).exists():
Labels_tool_.apn = Labels_tool_.objects.filter(map_id_labels = labmapid , layer_id_labels = layerid).update(apn=ApN)
Labels_tool_.owner_name = Labels_tool_.objects.filter(map_id_labels=labmapid, layer_id_labels=layerid).update(owner_name=OwnerName)
Labels_tool_.mailing_addr_One = Labels_tool_.objects.filter(map_id_labels=labmapid,
layer_id_labels=layerid).update(mailing_addr_One=MailingAddrOne)
Labels_tool_.mailing_addr_Two = Labels_tool_.objects.filter(map_id_labels=labmapid,
layer_id_labels=layerid).update(mailing_addr_Two=mailingaddrTwo)
Labels_tool_.situs_addr_One = Labels_tool_.objects.filter(map_id_labels=labmapid, layer_id_labels=layerid).update(situs_addr_One=situsaddrOne)
Labels_tool_.situs_addr_Two = Labels_tool_.objects.filter(map_id_labels=labmapid, layer_id_labels=layerid).update(situs_addr_Two=situsaddrTwo)
else:
labels_tool = Labels_tool_()
labels_tool.apn = self.request.POST.get('apn')
labels_tool.owner_name = self.request.POST.get('owner_name')
labels_tool.mailing_addr_One= self.request.POST.get('mailing_addr_One')
labels_tool.mailing_addr_Two= self.request.POST.get('mailing_addr_Two')
labels_tool.situs_addr_One = self.request.POST.get('situs_addr_One')
labels_tool.situs_addr_Two = self.request.POST.get('situs_addr_Two')
labels_tool.map_id_labels = self.map.id
labels_tool.layer_id_labels = self.layer.id
labels_tool.save()
# self.form = self.layer.form(self.request.POST)
return self.redirect('mapport.maps.layers.importlabel', self.map.id, self.layer.id)
return self.render('mapport/maps/layers/Labels_detail.html')
And template file is
<form action="" method="post" id="label_form">{% csrf_token %}
<div id="field1"><p id="apn_text">APN: </p> {{ form.apn}}</div>
Models are like
class pdftabel_tool_(models.Model):
apn = models.CharField(null=True, blank=False, max_length=255)
Now where I am making mistake that value from view.py is correct but not dropdown showing ?
You need to set self.fields, not self.initial.
You should define the field in the normal way at class level, then modify the queryset in the init method.
class labelModelForm(forms.ModelForm):
apn = forms.ModelChoiceField(queryset=Field.objects.none())
def __init__(self, *args, **kwargs):
layer_id = kwargs.pop('layer_id', None)
super(labelModelForm, self).__init__(*args, **kwargs)
self.fields['apn'].queryset = Field.objects.filter(layer=layer_id)

rendered slugs are not correct in url django

Why do I always have an extra %2F in my generated slugs urls?
All the slugs are generating correctly below when I print them out in the terminal, but I don't know why the url has the extra %2F
Something is wrong somewhere but I cannot seem to spot it
In my view i am using <a href = "{{ group.get_absolute_url }}">... to get the slug. Now, this works but outputs the above problem. If i do href = "{% url 'group' group.slug %} this throws an error that it can't find a reverse match.
Example: title of group is a group the url will be ../%2Fgroup/a-group/
in urls.py
(r'^/group/(?P<slug>[-\w\d]+)/$', "group"),
model
class BlogGroup(models.Model):
title = BleachField()
image = models.ImageField(upload_to="uploads/group_images", default="uploads/group_images/none/none.jpg")
created = models.DateTimeField(default = datetime.now)
slug = models.SlugField(unique = True)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("blog.views.group", kwargs = {'slug':self.slug})
form
class BlogGroupForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(BlogGroupForm, self).__init__(*args, **kwargs)
self.fields["title"].requried = True
self.fields["image"].required = True
self.fields["title"].widget = forms.TextInput()
class Meta:
model = BlogGroup
fields = ["title", "image", "slug"]
def save(self, commit = False):
instance = super(BlogGroupForm, self).save(commit = False)
return truncate_slug(instance, BlogGroup)
utils.py
from django.utils.text import slugify
import itertools
def truncate_slug(instance, arg):
length = arg._meta.get_field('slug').max_length
instance.slug = original_slug = slugify(instance.title)[:length]
for x in itertools.count(1):
if not arg.objects.filter(slug = instance.slug).exists():
break
instance.slug = "%s-%d" % (original_slug[:length - len(str(x)) -1], x)
instance.save()
return instance
You have a forward slash at the beginning of your regex. If you remove it, it should prevent the %2f (note that %2f is a url encoded forward slash).
url(r'^group/(?P<slug>[-\w]+)/$', "group", name="group"),
Note that I have also
removed \d, since \w already includes digits 0-9
used url() (best practice for Django 1.8+) and named the url pattern. That should hopefully make reversing the url with the {% url %} tag work. Using group.get_absolute_url in your template is fine though, there's no need to use the url tag if you don't want to.

How to access a field from a Model when calling it's parent

I am creating a basic cms/wiki as a learning project. Please forgive my noobish questions.
My wiki has pages. There are different types of pages. They have some fields in common and some unique fields.
I've included three of my models to demonstrate how I've undertakes this. (one model with the common fields that the actual pages inherit from)
class DefaultPage(models.Model):
title = models.CharField(max_length=100)
created_date = models.DateTimeField(auto_now_add=True, auto_now=False)
edited_date = models.DateTimeField(auto_now_add=False,auto_now=True)
child_pages = models.ManyToManyField("self",blank=True)
slug = models.SlugField(max_length=100,editable=False,blank=True)
def __unicode__ (self):
return self.title
def save(self, *args, **kwargs):
if not self.id:
self.slug = slugify(self.title)
super(DefaultPage, self).save(*args, **kwargs)
class Page(DefaultPage):
body = models.TextField(blank=True)
class LearningObject(DefaultPage):
archivefile = models.FileField(upload_to='static/learningobject/archivefiles/%Y/%m/%d')
indexpath = models.CharField(max_length=254,editable=False)
def unpackarchive(self):
archive = self.archivefile
filename = os.path.basename(str(archive))
folder = str(filename).split(".")[0]
print folder
index_found = "False"
with zipfile.ZipFile(archive,"r") as z:
for each in z.namelist():
if each == "index.html" or each == "index.htm":
index_found = "True"
else:
pass
if not index_found:
print "zip file does not contain a valid index.html file"
else:
path = os.path.join("static","learningobject","unpackedarchives",folder)
z.extractall(path)
self.findindex(path)
def findindex(self,path):
print path
for root, dirnames, filenames in os.walk(path):
for filename in fnmatch.filter(filenames, 'index.ht*'):
print filename
self.indexpath = os.path.join(root, filename)
print self.indexpath
def save(self, *args, **kwargs):
self.unpackarchive()
super(LearningObject, self).save(*args, **kwargs)
My urls.py passes the defaultpage.slug to
url(r'^(?P<default_page_slug>[\w\-]+)/$', views.defaultpageview, name='defaultpageview'),
a view that DefaultPage.objects.get(slug=default_page_slug)
def defaultpageview(request, default_page_slug):
context_dict = {}
try:
default_page = DefaultPage.objects.get(slug=default_page_slug)
context_dict['default_page'] = default_page
except:
pass
return render(request,'wiki/default_page.html',context_dict)
which in turn ends up in a template
<!DOCTYPE html>
<html>
<head>
<title>{{default_page.title}}</title>
</head>
<body>
<h1>{{default_page.title}}</h1>
{% if default_page.body %}
<p>
{{default_page.body}}
<p>
{%elif default_page.indexpath %}
{{default_page.indexpath}}
{% endif %}
</body>
</html>
However I am unable to call default_page.indexpath or default_page.body
Am I able to use the method I am attempting or do I need to pass all Models across in the view rather than the parent?
Sorry if the terms I've used are not correct. Please feel free to edit to correct me.
You're quering for DefaultPage objects, so that's what you get. A DefaultPage object doesn't have any of those fields; only the subclasses do. If you want to use body, you'll need to query for the class that contains that field, and the same for indexpath.

Categories

Resources