如何在django中创建一个关税计算器?

时间:2009-05-06 03:46:22

标签: django django-models

基本上我正在为我国的公用事业公司创建一个关税计算器,基于累进费率表,下面给出一个例子

2.(a)在任何一个月内,少于1,001加仑的费用........................... .. ... $ 9.23

(b)此后每加仑加仑的比例费用高达2,000加仑,按每1000加仑的比率计算.................. .. $ 15.89

(c)每加仑2,000加仑以及每加仑加仑3000加仑的每加仑的比例费用,按每1000加仑的比率计算。......... .. $ 17.43

(d)每加仑3000加仑以上加仑加4,000加仑的比例费用,按每1000加仑计算。......... .. $ 18.45

(e)每加仑4,000加仑以及每加仑加仑5,000加仑的每加仑的比例费用....... .. $ 19.48

(f)每加仑5,000加仑以及每加仑6,000加仑每加仑的比例费用,按每1000加仑计算。......... .. $ 20.50

(p)每加仑高于6,000加仑和高达7,000加仑的每加仑的比例费用,按每1000加仑的比率计算。......... .. $ 21.01

(h)每加仑7,000加仑以及每加仑加仑8,000加仑的每加仑的比例费用,每1000加仑的比率........... $ 21.53

(i)每加仑8,000以上加仑的比例费用,每1000加仑... $ 22.04

我正在考虑使用以下字段来执行Rate模型:

  1. 供应区域
  2. 描述
  3. from_gallons(加仑的起始范围)
  4. to_gallons(加仑的最终范围)
  5. rate_per_1000g
  6. 我的观点会接受来自加仑数量,供应区域的表格的帖子,并应回复从费率表中计算的使用量。

    我会在视图中做这样的事情

    from models import Rate    
    def tarrif_calc(request,gallons,area):
        rate = Rate.objects.get(area_of_supply=area, from_gallons >= gallons, to_gallons <= gallons)
        rate_per_gal = rate.rate_per_1000g/1000
        usage = gallons * rate_per_gal
        return usage
    

    这是我能想到的最简单的事情,但是我不确定如何处理渐进率?任何想法?我是在正确的轨道上吗?

2 个答案:

答案 0 :(得分:1)

业务规则应以代码表示。 More info

在仔细阅读你的问题之后,看起来你可能有许多这样的表需要查询。将许多类似的此类结构合法地放入数据库中。现在我假设你有。如果你真的只有一个表,那么案例分析可能是最简洁的。

在我自己的django应用程序中,我发现将业务逻辑放在一个非常自然的地方。模型看起来很明显,但很少能够获得必要的上下文,以便做出明智的决定。

通常我会把它分成几个依赖的应用程序。一个应用程序提供非常高级,抽象的模型和表单。另一个应用程序使用业务规则扩展了第一个表单。

第一个问题是查询Rate模型。这段代码实际上并不起作用。你不能在python中传递惰性比较。 Django has a mechanism for that,通过修改参数名称。

rate = Rate.objects.get(area_of_supply=area, from_gallons__gte=gallons, to_gallons__lte=gallons)

我不确定你的数据库是什么样的,但要确保有一个关于from_gallons和to_gallons的索引,否则这个查询会非常慢。

你的例子听起来并没有真正改变国家。如果这是真的,那么你可能应该使用GET视图而不是POST。

在任何一种情况下,逻辑的第一部分都是相同的。接收请求并验证表单输入。

# in "myproject/businessrules/forms.py"
from django import forms
from myproject.otherapp.models import Area

class RateForm(forms.Form):
    # declare as instance variables the data actually posted
    quantity = forms.DecimalField(label="amount of gallons")
    area = forms.ModelChoiceField(label="area of supply", queryset=Area.objects.all() )
    # now add the business rule!
    def clean(self):
        cleaned_data = self.cleaned_data # quantity and area area already validated 
        rate = Rate.objects.get(
                            area_of_supply=cleaned_data["area"],
                            from_gallons__gte=cleaned_data["gallons"],
                            to_gallons__lte=cleaned_data["gallons"])
        usage = cleaned_data["gallons"] * rate.rate_per_1000g/1000
        cleaned_data["usage"] = usage
        return cleaned_data

现在所需要的只是实际使用它。

# in "myproject/myapp/views.py"
from django.shortcuts import render_to_response
from businessrules import RateForm

def tarrif_view(request):
    form = RateForm(request.GET)
    if form.is_valid():
        context = { "form": form, "valid": True, "usage":form.cleaned_data["usage"] }
    else:
        context = { "form": form, "valid": False }
    return render_to_response("tarrif.html", context)

视图中嵌入了很少的业务知识。只有表格的事实 将清理后的计算结果存储在其“使用”键中。但由于这种观点恰恰是为了获得这种价值,所以这是正确的做法。

还需要使用表单的模板。 (我的django模板技能只是马马虎虎。如我所说,我更喜欢jinja2,所以你应该这样做)

就个人而言,我不太喜欢将单个表单结果移动到模板上下文中,我只是使用整个处理过的表单。我在jinja2中编写自己的模板,所以如果你的模板设计师不值得信任,你可能想要比这更谨慎地制作你的上下文。

{# in "myproject/templates/tarrif.html" #}
{% if valid %}
Usage: {{ usage }} dollars.
{% else %}
<form action="" method="GET">
    {{ form }}
    <input type="submit" \>
</form>
{% endif %}

同样,模板中不会出现比视图中更多的业务逻辑。

答案 1 :(得分:0)

现在来自@TokenMacGuy的一个非常完整的例子。我明白了你对表单中业务逻辑的意思。虽然我认为你没有说明累积费率,这将使它更长。

我在完成问题之后回答了我自己的问题,并希望其他人可以输入并启发django用户关于业务逻辑案例。

所以我做了什么:

首先创建一个费率模型,以便将其存储在数据库中。我用速率级别标记每个费率,以便能够处理累进评级。

class Rate(models.Model):
    area_of_supply = models.ForeignKey(SupplyArea)
    description = models.TextField()
    rate_level = models.CharField(max_length=2,choices=RATE_LEVEL_CHOICES,)
    rate_per_1k_gallons = models.DecimalField(max_digits=10,decimal_places=2)

然后我在我的views.py中创建了将处理来自表单的请求的视图(在我的例子中是ajax和常规形式)。和“业务逻辑”一样,在我的例子中是“traffic_calc()”

def tariff(request):
    if request.method == 'POST':
        form = TariffForm(request.POST)
        if form.is_valid():
            gallons = form.cleaned_data['gallons']
            gallons = int(gallons)
            area_id = form.cleaned_data['tariff']
            area = area_id.name
            usage = tarrif_calc(request, area_id, gallons)    
            response_dict = {'gallons': gallons,'area': area,'usage': usage}
            if request.is_ajax():
                return HttpResponse(simplejson.dumps(response_dict), mimetype='application/json')
            return render_to_response('rates/tariff_form.html', response_dict)
    else:
        form = TariffForm()
    return render_to_response('rates/tariff_form.html', {'form': form})

def tarrif_calc(request, area, gallons):
    r_levels = gallons//1000
    remainder = gallons%1000
    usage = 0
    i = 1

    if r_levels < 1:
        rate = Rate.objects.get(area_of_supply=area,rate_level=1)
        usage = rate.rate_per_1k_gallons    
    else:
        if r_levels >= 8:
            while i <= 9:
                rate = Rate.objects.get(area_of_supply=area,rate_level=i)
                usage += rate.rate_per_1k_gallons
                i += 1

            if gallons > 9000:
                remainder = gallons - 9000
            remainder_rate = Rate.objects.get(area_of_supply=area,rate_level=9)
            usage += remainder * remainder_rate.rate_per_1k_gallons/1000
            usage = round(usage,2)
        else:    
            while i <= r_levels:
                rate = Rate.objects.get(area_of_supply=area,rate_level=i)
                usage += rate.rate_per_1k_gallons
                i += 1
            remainder_level = r_levels+1
            if remainder_level >= 9:
                remainder_rate = Rate.objects.get(area_of_supply=area,rate_level=9)
            else:
                remainder_rate = Rate.objects.get(area_of_supply=area, rate_level=remainder_level)    
                usage += remainder * remainder_rate.rate_per_1k_gallons/1000
                usage = round(usage,2)
    return usage

我同意@TokenMacGuy ..我本应该使用GET,但我使用POST我猜是因为如果js不可用,常规表单也可以。我同意在这个级别@TokenMacGuy可能只是从视图导入tariff_calc并在他的forms.py中使用它。

然后我创建了必要的表单和模板以及处理ajax发布的javascript(虽然没有必要)

// JavaScript Document
$(document).ready(function()    {

$('#tariff_form').submit(function(event){
    event.preventDefault();  // stop the form from submitting and refreshing the page
    var form = this;               // in jQuery, this refers to the current element, which is #article_form

    // grab each form value
    var data = {};
    gallons = $('#id_gallons').val();
    tariff = $('#id_tariff').val();

    // now send the data to the server via AJAX
    if(gallons && tariff)
    {
        $.ajax({
            type: "POST",
            url: "/tariff-calculator/",
            data: "gallons="+gallons+"&tariff="+tariff,
            dataType: "json",
            success: function(json){
                $('#gallons_cont').html(json['gallons']);
                $('#area_cont').html(json['area']);
                $('#usage_cont').html(json['usage'])
                $('#results_json').show('slow');            
            },
            });
    }
    else
    {
        alert('Please Fill All Fields')
    }
}); 

});

我猜这两种方法都很相似并且都有效(虽然我没有试过@ TokenMacGuy),除了tariff_calc()函数外,似乎MackGuy解决了这个问题所以我会给他正确的答案,尽管我我会喜欢在forms.py中更多关于业务逻辑的反馈,因为我并不完全相信,或者认为存在巨大差异。