Poula Adel
Poula Adel

Reputation: 639

Flutter & DRF full stack - Flutter Error: type 'Null' is not a subtype of type 'String' in type cast

I'm using Djangorestframework (DRF) as backend and flutter with Getx package as frontend. in the DB i have a model that contains image and file fields.

in my models.py:

class Member(models.Model):
    FATHER = 0
    MOTHER = 1
    SON = 2
    DAUGHTER = 3

    FAMILY_MEMBER = (
        (FATHER, _("Father")),
        (MOTHER, _("Mother")),
        (SON, _("Son")),
        (DAUGHTER, _("Daughter")),
    )
    
    family = models.ForeignKey(Family, on_delete=models.CASCADE)
    name = models.CharField(_("Name"), max_length=255)
    relation = models.PositiveSmallIntegerField(
        _("Role"), choices=FAMILY_MEMBER, default=FATHER
    )
    contact = models.CharField(_("Contact"), max_length=12)
    nid = models.FileField(_("National ID"), upload_to="ids/")  # PDF
    face_img = models.ImageField(_("Face Image"), upload_to="faces/")  # Image
    age = models.PositiveIntegerField(_("Age"), default = 0)
    education = models.TextField(_("Education"), blank=True, null=True)
    health = models.TextField(_("Health"), blank=True, null=True)
    income = models.DecimalField(_("Income"), max_digits=10, decimal_places=2, default=0.00)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

in my models.dart:

class Member {
  final int? pk;
  final String name;
  final int family;
  final int relation;
  final String? contact;
  final String nid;
  final String? faceImg;
  final int age;
  final String? education;
  final double income;
  final String? health;
  final DateTime? createdAt;
  final DateTime? updatedAt;

  Member({
    this.pk,
    required this.name,
    required this.family,
    required this.relation,
    this.contact,
    required this.nid,
    this.faceImg,
    required this.age,
    this.education,
    this.health,
    required this.income,
    this.createdAt,
    this.updatedAt,
  });

  factory Member.fromJson(Map<String, dynamic> json) => Member(
        pk: json["id"] as int?,
        name: json["name"] as String,
        family: json["family"] as int,
        relation: json["relation"] as int,
        contact: json["contact"] as String? ?? '',
        nid: json["nid"] as String,
        faceImg: json["face_img"] as String?,
        age: json["age"] as int,
        education: json["education"] as String? ?? '',
        health: json["health"] as String? ?? '',
        income: json["income"] as double? ?? 0.0,
        createdAt: json['created_at'] != null
            ? DateTime.parse(json['created_at'])
            : null,
        updatedAt: json['updated_at'] != null
            ? DateTime.parse(json['updated_at'])
            : null,
      );

  Map<String, dynamic> toJson() => <String, dynamic>{
        "id": pk,
        "name": name,
        "family": family,
        "relation": relation,
        "contact": contact,
        "nid": nid,
        "face_img": faceImg,
        "age": age,
        "education": education,
        "health": health,
        "income": income.toString(),
        "created_at": createdAt?.toIso8601String(),
        "updated_at": updatedAt?.toIso8601String(),
      };
}

the list in screen that handle CRUD, member_screen.dart:

Obx(() {
          if (controller.isLoading.value) {
            return const Center(
              child: Padding(
                padding: EdgeInsets.all(8.0),
                child: CircularProgressIndicator(
                  semanticsLabel: "Loading",
                ),
              ),
            );
          } else if (controller.members.isEmpty) {
            return const Center(child: Text('No members found'));
          } else {
            return ListView.builder(
              shrinkWrap: true,
              physics: const NeverScrollableScrollPhysics(),
              itemCount: controller.members.length,
              itemBuilder: (context, index) {
                final member = controller.members[index];
                return ListTile(
                  title: Text('Member ${member.pk}'),
                  subtitle: Text(member.name),
                  leading: member.faceImg != null
                      ? CircleAvatar(
                          backgroundImage: NetworkImage(member.faceImg!),
                        )
                      : const CircleAvatar(
                          child: Icon(Icons.person),
                        ),
                  trailing: Row(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      IconButton(
                        color: Colors.green,
                        icon: const Icon(Icons.edit),
                        onPressed: () {
                          // Edit member
                          Get.bottomSheet(
                            MemberForm(
                              key: UniqueKey(),
                              member: member,
                            ),
                            backgroundColor: Colors.white,
                            isScrollControlled: true,
                          );
                        },
                      ),
                      IconButton(
                        color: Colors.red,
                        icon: const Icon(Icons.delete),
                        onPressed: () {
                          // Delete member
                          Get.defaultDialog(
                            title: "Delete Member",
                            middleText:
                                "Are you sure you want to delete this member?",
                            textCancel: "Cancel",
                            textConfirm: "Delete",
                            confirmTextColor: Colors.white,
                            onConfirm: () {
                              if (member.pk != null) {
                                controller.deleteMember(member.pk!);
                              }
                              Get.back();
                            },
                          );
                        },
                      ),
                    ],
                  ),
                  onTap: () {
                    Get.bottomSheet(
                      Padding(
                        padding: const EdgeInsets.all(16.0),
                        child: Column(
                          mainAxisSize: MainAxisSize.min,
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            Text('Member ${member.pk} Details',
                                style: const TextStyle(
                                    fontSize: 24, fontWeight: FontWeight.bold)),
                            const SizedBox(height: 16),
                            Text('Name: ${member.name}',
                                style: const TextStyle(fontSize: 18)),
                            const SizedBox(height: 8),
                            Text('Family: ${member.family}',
                                style: const TextStyle(fontSize: 18)),
                            const SizedBox(height: 8),
                            Text('Relation: ${member.relation}',
                                style: const TextStyle(fontSize: 18)),
                            const SizedBox(height: 8),
                            Text('Contact: ${member.contact ?? 'N/A'}',
                                style: const TextStyle(fontSize: 18)),
                            const SizedBox(height: 8),
                            Text('NID: ${member.nid}',
                                style: const TextStyle(fontSize: 18)),
                            const SizedBox(height: 8),
                            Text('Image URL: ${member.faceImg ?? 'N/A'}',
                                style: const TextStyle(fontSize: 18)),
                            const SizedBox(height: 8),
                            Text('Age: ${member.age}',
                                style: const TextStyle(fontSize: 18)),
                            const SizedBox(height: 8),
                            Text('Education: ${member.education ?? 'N/A'}',
                                style: const TextStyle(fontSize: 18)),
                            const SizedBox(height: 8),
                            Text('Income: ${member.income.toString()}',
                                style: const TextStyle(fontSize: 18)),
                            const SizedBox(height: 8),
                            Text('Health: ${member.health ?? 'N/A'}',
                                style: const TextStyle(fontSize: 18)),
                            const SizedBox(height: 8),
                            Text('Created At: ${member.createdAt}',
                                style: const TextStyle(fontSize: 18)),
                            const SizedBox(height: 8),
                            Text('Updated At: ${member.updatedAt ?? 'N/A'}',
                                style: const TextStyle(fontSize: 18)),
                          ],
                        ),
                      ),
                      backgroundColor: Colors.black87,
                      isScrollControlled: true,
                    );
                  },
                );
              },
            );
          }
        }),

I'm getting Error

flutter: type 'Null' is not a subtype of type 'String' in type cast

when i try to view the list of members in my member_controller.dart:

void fetchMembers() async {
    isLoading.value = true;
    try {
      var fetchedMembers = await _api.get('members');
      members.value = (fetchedMembers as List)
          .map((json) => Member.fromJson(json as Map<String, dynamic>))
          .toList();
    } catch (e) {
      print(e);
      Get.snackbar('Controller Error', 'Failed! ${e.toString()}');
    } finally {
      isLoading.value = false;
    }
  }

How to solve this Error. as Handling image and file fileds in my Member model between the backend and frontend. is the file the issue?

I've tried to change flutter field type using String? for path or using File both of them gives me issues. so I need experience to title the issue and the right way of handling it and best practice.

Upvotes: 0

Views: 21

Answers (0)

Related Questions