【发布时间】:2021-05-04 09:53:13
【问题描述】:
我有一个看法:
def create(self, request):
serializer = OrderPostSerializer(data=request.data)
if serializer.is_valid():
instance = serializer.save()
serializer = OrderDetailsSerializer(instance)
return AppResponse.success(
"Order created successfully.",
serializer.data,
http_success_code=status.HTTP_201_CREATED,
)
return AppResponse.error(
serializer.errors,
None,
http_error_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
)
序列化器:
class CustomerDetailsPostSerializer(serializers.Serializer):
id = serializers.IntegerField(
required=False, error_messages={"invalid": "id should be a valid integer."}
)
name = serializers.CharField(required=False, max_length=80)
email = serializers.EmailField(required=False)
mobile = serializers.CharField(
required=False,
max_length=15,
error_messages={
"max_length": "mobile field should not exceed more than 15 characters."
},
)
company_name = serializers.CharField(
required=False,
max_length=255,
allow_null=True,
error_messages={
"max_length": "company name field should not exceed more than 255 characters."
},
)
def validate_email(self, value):
customer = Customer.objects
if self.instance:
customer = customer.exclude(pk=self.instance.pk)
if customer.filter(email__iexact=value):
raise serializers.ValidationError(
"Customer with this email already exists."
)
return value
def validate_company(self, value):
customer = Customer.objects
if self.instance:
customer = customer.exclude(pk=self.instance.pk)
if customer.filter(company_name__iexact=value):
raise serializers.ValidationError(
"Customer with this company name already exists."
)
return value
def validate_mobile(self, value):
if validate_phone_number(value) is None:
customer = Customer.objects
if self.instance:
customer = customer.exclude(pk=self.instance.pk)
if customer.filter(mobile__iexact=value):
raise serializers.ValidationError(
"Customer with this phone number already exists."
)
return value
def validate(self, data):
data = dict(data)
if ("id" not in data.keys() or not data.get("id")) and (
("name" not in data.keys() or not data.get("name"))
or ("email" not in data.keys() or not data.get("email"))
or ("mobile" not in data.keys() or not data.get("mobile"))
):
raise serializers.ValidationError(
"Either id or name, email and mobile are required in customer details."
)
return data
class ContactDetailsPostSerializer(serializers.Serializer):
id = serializers.IntegerField(
required=False, error_messages={"invalid": "id should be a valid integer."}
)
name = serializers.CharField(required=False, max_length=80, allow_null=True)
email = serializers.EmailField(required=False, allow_null=True)
mobile = serializers.CharField(
required=False,
max_length=15,
allow_null=True,
error_messages={
"max_length": "mobile field should not exceed more than 15 characters."
},
)
def validate_email(self, value):
contact = CustomerContact.objects
if self.instance:
contact = contact.exclude(pk=self.instance.pk)
if contact.filter(email__iexact=value):
raise serializers.ValidationError("Contact with this email already exists.")
return value
def validate_mobile(self, value):
if validate_phone_number(value) is None:
contact = CustomerContact.objects
if self.instance:
contact = contact.exclude(pk=self.instance.pk)
if contact.filter(mobile__iexact=value):
raise serializers.ValidationError(
"Contact with this phone number already exists."
)
return value
def validate(self, data):
data = dict(data)
if (
("id" not in data.keys() or not data.get("id"))
and ("name" not in data.keys() or not data.get("name"))
and ("email" not in data.keys() or not data.get("email"))
and ("mobile" not in data.keys() or not data.get("mobile"))
):
return data
raise serializers.ValidationError(
"Either id or name, email and mobile are required in contact details."
)
class DeliveryAddressDetailsPostSerializer(serializers.Serializer):
id = serializers.IntegerField(
required=False, error_messages={"invalid": "id should be a valid integer."}
)
title = serializers.CharField(required=False, max_length=100)
street = serializers.CharField(required=False, max_length=255)
suite = serializers.CharField(required=False, max_length=255)
city = serializers.CharField(required=False, max_length=255)
zipcode = serializers.CharField(required=False, max_length=10)
county = serializers.CharField(required=False, max_length=255)
state = serializers.CharField(required=False, max_length=255)
def validate_title(self, value):
address = Address.objects
if self.instance:
address = address.exclude(pk=self.instance.pk)
if address.filter(title__iexact=value).filter(type=AddressType.DELIVERY):
raise serializers.ValidationError(
"Delivery address with this title already exists."
)
return value
def validate(self, data):
data = dict(data)
if ("id" not in data.keys() or not data.get("id")) and (
("title" not in data.keys() or not data.get("title"))
or ("street" not in data.keys() or not data.get("street"))
or ("city" not in data.keys() or not data.get("city"))
or ("zipcode" not in data.keys() or not data.get("zipcode"))
or ("county" not in data.keys() or not data.get("county"))
or ("state" not in data.keys() or not data.get("city"))
):
raise serializers.ValidationError(
"Either id or title, street, city, zipcode, county and state are required in delivery details."
)
return data
class BillingAddressDetailsPostSerializer(serializers.Serializer):
id = serializers.IntegerField(
required=False, error_messages={"invalid": "id should be a valid integer."}
)
title = serializers.CharField(required=False, max_length=100)
street = serializers.CharField(required=False, max_length=255)
suite = serializers.CharField(required=False, max_length=255)
city = serializers.CharField(required=False, max_length=255)
zipcode = serializers.CharField(required=False, max_length=10)
county = serializers.CharField(required=False, max_length=255)
state = serializers.CharField(required=False, max_length=255)
payment_method = serializers.ChoiceField(required=False, choices=PaymentMethod)
def validate_title(self, value):
address = Address.objects
if self.instance:
address = address.exclude(pk=self.instance.pk)
if address.filter(title__iexact=value).filter(type=AddressType.BILLING):
raise serializers.ValidationError(
"Billing address with this title already exists."
)
return value
def validate(self, data):
data = dict(data)
if ("id" not in data.keys() or not data.get("id")) and (
("title" not in data.keys() or not data.get("title"))
or ("street" not in data.keys() or not data.get("street"))
or ("city" not in data.keys() or not data.get("city"))
or ("zipcode" not in data.keys() or not data.get("zipcode"))
or ("county" not in data.keys() or not data.get("county"))
or ("state" not in data.keys() or not data.get("state"))
# or ("payment_method" not in data.keys() or not data.get("payment_method"))
):
raise serializers.ValidationError(
"Either id or title, street, city, zipcode, county and state are required in billing details."
)
return data
class OrderPostSerializer(serializers.Serializer):
customer_details = CustomerDetailsPostSerializer()
delivery_address = DeliveryAddressDetailsPostSerializer()
# billing_same_as_delivery = serializers.ChoiceField(
# required=True, choices=BillingSameAsDelivery
# )
billing_address = BillingAddressDetailsPostSerializer()
contact_details = ContactDetailsPostSerializer()
dumpster_type = serializers.CharField(
required=False,
allow_null=True,
allow_blank=True,
error_messages={"required": "Dumpster type is required."},
)
order_type = serializers.CharField(
required=True, error_messages={"required": "Order type is required."}
)
delivery_date = serializers.DateField(
required=True,
error_messages={
"required": "Delivery date is required.",
"invalid": "Delivery date has wrong format. Use one of these formats instead: YYYY-MM-DD.",
},
)
preferred_time = serializers.ChoiceField(
required=False, choices=PreferredTime.choices, allow_null=True
)
renting_till = serializers.DateField(
required=False,
error_messages={
"invalid": "Renting till date has wrong format. Use one of these formats instead: YYYY-MM-DD.",
},
allow_null=True,
)
dumpster_cost = serializers.DecimalField(
required=True,
max_digits=8,
decimal_places=2,
error_messages={"required": "Dumpster cost is required."},
)
city_tax = serializers.DecimalField(
required=False, max_digits=8, decimal_places=2, allow_null=True
)
permit_tax = serializers.DecimalField(
required=False, max_digits=8, decimal_places=2, allow_null=True
)
class Meta:
# model = Order
exclude = []
def validate(self, data):
if data["renting_till"] and data["renting_till"] < data["delivery_date"]:
raise serializers.ValidationError(
"Renting till date should be greater than delivery date."
)
return data
def create(self, validated_data):
try:
with transaction.atomic():
# attach existing customer or create new customer
customer_details = validated_data.pop("customer_details")
customer = None
if "id" in customer_details.keys() and customer_details.get("id"):
try:
customer = Customer.objects.get(pk=customer_details.get("id"))
except Customer.DoesNotExist:
raise serializers.ValidationError("Invalid customer.")
else:
customer = Customer.objects.create(
name=customer_details.get("name"),
email=customer_details.get("email"),
mobile=customer_details.get("mobile"),
company_name=customer_details.get("company_name"),
)
# attach existing contact or create new contact
contact_details = validated_data.pop("contact_details")
contact = None
if "id" in contact_details.keys() and contact_details.get("id"):
try:
contact = CustomerContact.objects.get(
pk=contact_details.get("id")
)
except CustomerContact.DoesNotExist:
raise serializers.ValidationError("Invalid contact.")
elif (
"name" in contact_details.keys() and contact_details.get("name")
) and (
"mobile" in contact_details.keys() and contact_details.get("mobile")
):
contact = CustomerContact.objects.create(
name=contact_details.get("name"),
email=contact_details.get("email"),
mobile=contact_details.get("mobile"),
customer=customer,
)
# attach existing delivery address or create new delivery address
delivery_address_details = validated_data.pop("delivery_address")
delivery_address = None
if "id" in delivery_address_details.keys() and delivery_address_details.get(
"id"
):
try:
delivery_address = (
Address.objects.filter(type=AddressType.DELIVERY)
.filter(customer=customer)
.filter(pk=delivery_address_details.get("id"))
)
except Address.DoesNotExist:
raise serializers.ValidationError("Invalid delivery address.")
else:
county = None
try:
county = County.objects.get(
name=delivery_address_details.get("county")
)
except County.DoesNotExist:
raise serializers.ValidationError("Invalid county.")
delivery_address = Address.objects.create(
customer=customer,
title=delivery_address_details.get("title"),
street=delivery_address_details.get("street"),
suite=delivery_address_details.get("suite"),
city=delivery_address_details.get("city"),
zipcode=delivery_address_details.get("zipcode"),
county=county,
state=delivery_address_details.get("state"),
type=AddressType.DELIVERY,
)
# attach existing billing address or create new billing address
billing_address_details = validated_data.pop("billing_address")
billing_address = None
if "id" in billing_address_details.keys() and billing_address_details.get(
"id"
):
try:
billing_address = (
Address.objects.filter(type=AddressType.BILLING)
.filter(customer=customer)
.filter(pk=billing_address_details.get("id"))
)
except Address.DoesNotExist:
raise serializers.ValidationError("Invalid billing address.")
else:
county = None
try:
county = County.objects.get(
name=delivery_address_details.get("county")
)
except County.DoesNotExist:
raise serializers.ValidationError("Invalid county.")
if validated_data.get("billing_same_as_delivery"):
try:
billing_address = (
Address.objects.filter(type=AddressType.BILLING)
.filter(customer=customer)
.filter(title=delivery_address.title)
)
except Address.DoesNotExist:
billing_address = Address.objects.create(
customer=customer,
title=delivery_address.get("title"),
street=delivery_address.get("street"),
suite=delivery_address.get("suite"),
city=delivery_address.get("city"),
zipcode=delivery_address.get("zipcode"),
county=county,
state=delivery_address.get("state"),
payment_method=PaymentMethod.COD,
)
else:
billing_address = Address.objects.create(
customer=customer,
title=billing_address_details.get("title"),
street=billing_address_details.get("street"),
suite=billing_address_details.get("suite"),
city=billing_address_details.get("city"),
zipcode=billing_address_details.get("zipcode"),
county=county,
state=billing_address_details.get("state"),
payment_method=billing_address_details.get(
"payment_method"
),
)
dumpster_type = None
if validated_data.get("dumpster_type"):
try:
dumpster_type = DumpsterType.objects.get(
name=validated_data.get("dumpster_type")
)
except DumpsterType.DoesNotExist:
raise serializers.ValidationError("Invalid dumpster type.")
order_type = None
try:
order_type = OrderType.objects.get(
name=validated_data.get("order_type")
)
except OrderType.DoesNotExist:
raise serializers.ValidationError("Invalid order type.")
# create order instance
instance = Order.objects.create(
customer=customer,
contact=contact,
delivery_address=delivery_address,
billing_address=billing_address,
dumpster_type=dumpster_type,
order_type=order_type,
delivery_date=validated_data.get("delivery_date"),
preferred_time=validated_data.get("preferred_time"),
renting_till=validated_data.get("renting_till"),
dumpster_cost=validated_data.get("dumpster_cost"),
city_tax=validated_data.get("city_tax"),
permit_tax=validated_data.get("permit_tax"),
)
return instance
except DatabaseError as database_error:
print(database_error)
raise serializers.ValidationError(database_error)
我正在 OrderPostSerializer 的 create() 方法中为客户模型创建一个实例。创建客户实例时,我想将该实例传递给 DeliveryAddressDetailsPostSerializer() 以便我可以检查是否存在与客户具有相同标题的送货地址。
我怎样才能做到这一点?
【问题讨论】:
标签: django django-models django-rest-framework django-serializer