[Python] Flutter & DRF full stack - Flutter Error: type 'Null' is not a subtype of type...

Discussão em 'Python' iniciado por Stack, Fevereiro 26, 2025.

  1. Stack

    Stack Membro Participativo

    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.

    Continue reading...

Compartilhe esta Página