Dip*_*att 6 python django postgresql postgis psycopg2
所以我有一个复合字段,我想在我的 django 模型中使用 postgres 作为数据库。
CREATE TYPE address_verbose AS (
contact_person_name string_not_null,
mobile string_no_spaces,
mobile_cc string_no_spaces,
email email_with_check,
address text,
city text,
state text,
country text,
pincode string_no_spaces,
location geography
);
Run Code Online (Sandbox Code Playgroud)
、string_not_null和只是我为验证而创建的域string_no_spaces。email_with_check
如果我使用 SQL,一切都会很棒,但问题是想在 django 模型中使用这个字段,并且我想使用 Django ORM 至少创建、更新和删除包含该字段的对象。
因此,经过一些谷歌搜索后,我能够想出一个自定义模型字段。
from typing import Optional
from django.contrib.gis.geos import Point
from django.db import connection
from django.db import models
from psycopg2.extensions import register_adapter, adapt, AsIs
from psycopg2.extras import register_composite
address_verbose = register_composite(
'address_verbose',
connection.cursor().cursor,
globally=True
).type
def address_verbose_adapter(value):
return AsIs("(%s, %s, %s, %s, %s, %s, %s, %s, %s, ST_GeomFromText('POINT(%s %s)', 4326))::address_verbose" % (
adapt(value.contact_person_name).getquoted().decode('utf-8'),
adapt(value.mobile).getquoted().decode('utf-8'),
adapt(value.mobile_cc).getquoted().decode('utf-8'),
adapt(value.email).getquoted().decode('utf-8'),
adapt(value.address).getquoted().decode('utf-8'),
adapt(value.city).getquoted().decode('utf-8'),
adapt(value.state).getquoted().decode('utf-8'),
adapt(value.country).getquoted().decode('utf-8'),
adapt(value.pincode).getquoted().decode('utf-8'),
adapt(value.location).getquoted().decode('utf-8'),
))
register_adapter(address_verbose, address_verbose_adapter)
class AddressVerbose:
def __init__(self, contact_person_name: str, mobile: str, mobile_cc: str, email: str, address: str, city: str,
state: str, country: str, pincode: str, location: Optional[Point] = None):
self.contact_person_name = contact_person_name
self.mobile = mobile
self.mobile_cc = mobile_cc
self.email = email
self.address = address
self.city = city
self.state = state
self.country = country
self.pincode = pincode
self.location = location
class AddressVerboseField(models.Field):
def from_db_value(self, value, expression, connection):
if value is None:
return value
return AddressVerbose(
value.contact_person_name,
value.mobile,
value.mobile_cc,
value.email,
value.address,
value.city,
value.state,
value.country,
value.pincode,
value.location,
)
def to_python(self, value):
if isinstance(value, AddressVerbose):
return value
if value is None:
return value
return AddressVerbose(
value.contact_person_name,
value.mobile,
value.mobile_cc,
value.email,
value.address,
value.city,
value.state,
value.country,
value.pincode,
value.location,
)
def get_prep_value(self, value):
if not isinstance(value, AddressVerbose):
return None
return (
value.contact_person_name,
value.mobile,
value.mobile_cc,
value.email,
value.address,
value.city,
value.state,
value.country,
value.pincode,
# Attempt 1
value.location,
# Attempt 2
# "ST_GeomFromText('POINT(%s %s)', 4326)" % (value.location[0], value.location[1])
)
def db_type(self, connection):
return 'address_verbose'
Run Code Online (Sandbox Code Playgroud)
使用上述字段的最小模型是
class Shipment(models.Model):
pickup_detail = AddressVerboseField()
drop_detail = AddressVerboseField()
Run Code Online (Sandbox Code Playgroud)
如果我要删除位置字段,那么在创建、更新或获取货件对象时一切都工作得很好。但是当您将位置字段包含在AddressVerboseField. 从 django doc 中,我得到了摆弄的想法get_prep_value,我尝试了第一种方法,直接发送元组中的位置。但它引发了以下错误。
psycopg2 的适应函数似乎无法解析 Point 字段,因此考虑在尝试 2 中直接发送点字段的 SQL 文本。这让我很接近,但生成的 sql 中存在额外的引号。
我在 google 中搜索了很多有关将 postgres 的复合字段适应 django 的信息,但所有结果并不真正包含 postgres 的 postgis 部分中存在的字段。这是我第一次编写 django 自定义字段,因此我可能会丢失或不正确的某些逻辑。如果有人能帮助我解决这个问题或者为我指出正确的方向,那将非常有帮助。谢谢
| 归档时间: |
|
| 查看次数: |
301 次 |
| 最近记录: |