You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django中通过外键实现大洲→国家→城市层级页面关联

问题解决与层级关联实现指南

一、修复外键查询错误

你当前用country.objects.filter(ckey='as45914')报错,核心原因是外键字段ckey关联的是Continents模型实例,直接传字符串会触发类型不匹配。正确查询方式有两种:

  1. 通过关联模型的主键字段查询(利用双下划线指定关联字段):
    first_person = country.objects.filter(ckey__ckey='as45914')
    
  2. 先获取目标大洲实例,再关联查询:
    continent = Continents.objects.get(ckey='as45914')
    first_person = country.objects.filter(ckey=continent)
    

另外建议修正模型命名:country类名改为大写开头的Country,符合Python类命名规范,避免后续逻辑混淆。

二、实现「大洲→国家→城市」层级跳转

要实现层级页面跳转,核心是通过URL传递层级标识(如主键),在视图中根据标识查询对应层级数据,再渲染到页面。以下是完整实现步骤:

1. 完善模型结构(补充城市模型)

先补充城市模型,形成完整层级关系:

from django.db import models

class Continent(models.Model):  # 修正类名大写
    ckey = models.CharField(max_length=10, primary_key=True)
    continentName = models.CharField(max_length=50)

    def __str__(self):
        return self.continentName

class Country(models.Model):  # 修正类名大写
    countryNum = models.IntegerField(primary_key=True)
    countryName = models.CharField(max_length=15)
    countryBrief= models.TextField(max_length=500)
    currency = models.CharField(max_length=15)
    cost = models.FloatField()  # FloatField无需max_length参数
    cultures = models.TextField(max_length=300)
    rulesBrief = models.TextField(max_length=200)
    location = models.TextField(max_length=500)
    # 重命名外键字段为continent,添加related_name方便反向查询
    continent = models.ForeignKey(Continent, on_delete=models.PROTECT, related_name='countries')

    def __str__(self):
        return self.countryName

class City(models.Model):
    cityId = models.IntegerField(primary_key=True)
    cityName = models.CharField(max_length=20)
    cityBrief = models.TextField(max_length=300)
    country = models.ForeignKey(Country, on_delete=models.PROTECT, related_name='cities')

    def __str__(self):
        return self.cityName

2. 配置层级URL路由

在urls.py中定义带参数的路由,传递父级数据的主键:

from django.urls import path
from . import views

urlpatterns = [
    path('', views.home, name='home'),
    path('continents/', views.continent_list, name='continent_list'),
    # 传递大洲ckey,查询该大洲下的国家
    path('continents/<str:continent_ckey>/countries/', views.country_list_by_continent, name='country_list_by_continent'),
    # 传递国家num,查询该国家下的城市
    path('countries/<int:country_num>/cities/', views.city_list_by_country, name='city_list_by_country'),
]

3. 编写视图函数

根据URL参数查询对应层级的数据:

from django.shortcuts import render, get_object_or_404
from .models import Continent, Country, City

def home(request):
    return render(request,"guide/home.html")

def continent_list(request):
    continents = Continent.objects.all()
    return render(request,"guide/continent_list.html",{'continents': continents})

# 根据大洲ckey查询下属国家
def country_list_by_continent(request, continent_ckey):
    continent = get_object_or_404(Continent, ckey=continent_ckey)
    # 利用related_name反向查询国家集合
    countries = continent.countries.all()
    return render(request,"guide/country_list.html",{'continent': continent, 'countries': countries})

# 根据国家num查询下属城市
def city_list_by_country(request, country_num):
    country = get_object_or_404(Country, countryNum=country_num)
    # 利用related_name反向查询城市集合
    cities = country.cities.all()
    return render(request,"guide/city_list.html",{'country': country, 'cities': cities})

4. 编写层级页面模板

(1)大洲列表页continent_list.html

展示所有大洲,点击跳转至对应大洲的国家列表:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>大洲列表</title>
</head>
<body>
    <h1>世界大洲</h1>
    <ul>
        {% for continent in continents %}
            <li>
                <a href="{% url 'country_list_by_continent' continent.ckey %}">{{ continent.continentName }}</a>
            </li>
        {% endfor %}
    </ul>
</body>
</html>

(2)国家列表页country_list.html

展示当前大洲下的国家,点击跳转至对应国家的城市列表:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>{{ continent.continentName }} - 国家列表</title>
</head>
<body>
    <h1>{{ continent.continentName }}的国家</h1>
    <a href="{% url 'continent_list' %}">返回大洲列表</a>
    <ul>
        {% for country in countries %}
            <li>
                <a href="{% url 'city_list_by_country' country.countryNum %}">{{ country.countryName }}</a>
                <p>{{ country.countryBrief }}</p>
            </li>
        {% empty %}
            <li>暂无国家数据</li>
        {% endfor %}
    </ul>
</body>
</html>

(3)城市列表页city_list.html

展示当前国家下的城市:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>{{ country.countryName }} - 城市列表</title>
</head>
<body>
    <h1>{{ country.countryName }}的城市</h1>
    <a href="{% url 'country_list_by_continent' country.continent.ckey %}">返回国家列表</a>
    <ul>
        {% for city in cities %}
            <li>
                <h3>{{ city.cityName }}</h3>
                <p>{{ city.cityBrief }}</p>
            </li>
        {% empty %}
            <li>暂无城市数据</li>
        {% endfor %}
    </ul>
</body>
</html>

三、关键知识点总结

  1. 外键查询规范:查询外键关联数据时,要么传递关联模型实例,要么用双下划线指定关联模型的字段;
  2. 层级路由设计:通过URL参数传递父级数据主键,实现动态查询子级数据;
  3. 反向查询优化:利用related_name可直接从父模型获取子模型集合,简化查询逻辑;
  4. 模板URL跳转:使用{% url %}模板标签生成动态URL,避免硬编码路径,提升可维护性。

内容的提问来源于stack exchange,提问作者mq10

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 22:01:16