给 Odoo 开发者的快速上手指南
这个页面专门为有 Python/Odoo 经验的开发者准备。如果你熟悉 Odoo 开发,这里会帮你快速建立 C#/Avalonia 的心智模型。
核心概念映射
| Odoo/Python | C#/Avalonia | 说明 |
|---|---|---|
models.Model | class | 数据模型定义 |
fields.Char | string | 字符串字段 |
fields.Integer | int | 整数字段 |
fields.Float | double 或 decimal | 小数字段 |
fields.Boolean | bool | 布尔字段 |
fields.Many2one | 对象引用 | 关联关系 |
fields.One2many | List<T> | 一对多关系 |
@api.depends | INotifyPropertyChanged | 属性变化通知 |
self.env | 依赖注入(DI) | 服务访问 |
| XML 视图 | AXAML | UI 定义 |
search() | LINQ | 数据查询 |
create() | new | 创建对象 |
代码对比示例
1. 定义模型
Odoo
class Partner(models.Model):
_name = 'res.partner'
_description = 'Partner'
name = fields.Char(string='Name', required=True)
email = fields.Char(string='Email')
age = fields.Integer(string='Age')
is_company = fields.Boolean(string='Is Company')
def get_display_name(self):
return f"{self.name} ({self.email})"关键差异:
- C# 用
{ get; set; }定义属性,不是字段 - C# 用
?表示可空类型(如string?) - C# 方法名用 PascalCase(
GetDisplayName),Python 用 snake_case(get_display_name)
2. 创建记录
Odoo
# Odoo
partner = self.env['res.partner'].create({
'name': 'Tom',
'email': 'tom@example.com',
'age': 25
})3. 查询数据
Odoo
# Odoo
partners = self.env['res.partner'].search([
('age', '>', 18),
('is_company', '=', False)
])
# 获取第一个
first = partners[0] if partners else None
# 遍历
for partner in partners:
print(partner.name)关键差异:
- Odoo 用 domain 语法
[('field', 'op', value)] - C# 用 LINQ 的 lambda 表达式
p => p.Age > 18 - C# 的
FirstOrDefault()类似 Odoo 的partners[0] if partners else None
4. 更新记录
Odoo
# Odoo
partner.write({
'name': 'New Name',
'age': 26
})5. 删除记录
Odoo
# Odoo
partner.unlink()语法差异速查
变量声明
Python
# Python - 动态类型
name = "Tom"
age = 18
price = 19.99
is_active = True
# 可以随时改类型
name = 123 # 合法条件判断
Python
# Python
if age >= 18:
print("成年")
elif age >= 13:
print("青少年")
else:
print("儿童")差异:
- C# 条件必须加括号
() - C# 代码块必须用花括号
{} - C# 用
else if,不是elif
循环
Python
# Python
for i in range(5):
print(i)
for name in names:
print(name)
while count > 0:
count -= 1函数/方法
Python
# Python
def calculate_total(price, quantity):
return price * quantity
def greet(name="Guest"):
return f"Hello, {name}"差异:
- C# 必须声明返回类型(
double、string) - C# 方法名用 PascalCase
- C# 参数必须声明类型
列表/集合
Python
# Python
names = []
names.append("Tom")
names.append("Alice")
print(len(names))
print(names[0])
# 字典
users = {}
users[1] = "Tom"
users[2] = "Alice"思维转换
1. 从动态到静态
Python/Odoo:
- 运行时才知道类型
- 灵活但容易出错
C#:
- 编译时就确定类型
- IDE 能提前发现错误
- 代码提示更准确
好处: 大型项目更安全,重构更容易
2. 从 ORM 到手动管理
Odoo:
- 框架自动处理数据库
self.env['model'].search()
C#:
- 需要选择 ORM(如 Entity Framework)
- 或者手动写 SQL
好处: 更灵活,性能可控
3. 从服务端到客户端
Odoo:
- 代码运行在服务器
- 用户通过浏览器访问
- 需要网络连接
Avalonia:
- 代码运行在用户电脑
- 不需要网络
- 响应更快
好处: 离线可用,性能更好
4. 从 MVC 到 MVVM
Odoo:
- Model(模型)
- View(XML 视图)
- Controller(Python 控制器)
Avalonia:
- Model(数据模型)
- View(AXAML 视图)
- ViewModel(视图模型,连接 Model 和 View)
核心区别: MVVM 用数据绑定,不需要手动更新 UI
常见困惑解答
Q1: 为什么要写这么多类型?
A: 静态类型能在编译时发现错误。
# Python - 运行时才报错
def add(a, b):
return a + b
result = add("hello", 5) # 运行时报错// C# - 编译时就报错
public int Add(int a, int b)
{
return a + b;
}
// int result = Add("hello", 5); // 编译错误,提前发现Q2: 没有 self.env 怎么办?
A: C# 使用依赖注入(Dependency Injection)。
# Odoo
partner = self.env['res.partner'].browse(1)// C# (后面会学)
public class MyService
{
private readonly IPartnerRepository _repo;
public MyService(IPartnerRepository repo)
{
_repo = repo; // 依赖注入
}
public Partner GetPartner(int id)
{
return _repo.GetById(id);
}
}Q3: UI 怎么定义?
A: 用 AXAML(类似 Odoo 的 XML 视图)。
<!-- Odoo XML -->
<record id="view_partner_form" model="ir.ui.view">
<field name="name">partner.form</field>
<field name="model">res.partner</field>
<field name="arch" type="xml">
<form>
<field name="name"/>
<field name="email"/>
</form>
</field>
</record><!-- Avalonia AXAML -->
<Window xmlns="https://github.com/avaloniaui">
<StackPanel>
<TextBox Text="{Binding Name}" />
<TextBox Text="{Binding Email}" />
</StackPanel>
</Window>Q4: 数据库怎么操作?
A: 用 Entity Framework Core(类似 Odoo ORM)。
# Odoo
partners = self.env['res.partner'].search([('age', '>', 18)])// C# Entity Framework
var partners = dbContext.Partners
.Where(p => p.Age > 18)
.ToList();学习路径建议
Week 1-2: 适应 C# 语法
- 最痛苦的阶段
- 习惯静态类型
- 习惯花括号和分号
- 对应 Odoo: 类似刚学 Python 时的语法适应期
Week 3-4: 理解 OOP
- 类、对象、继承
- 对应 Odoo: 和
models.Model类似
Week 5-6: 学习 MVVM
- 数据绑定
- 命令模式
- 对应 Odoo: 类似 Odoo 的 MVC,但更自动化
Week 7-8: 数据持久化
- Entity Framework
- LINQ 查询
- 对应 Odoo: 类似 Odoo ORM
Week 9-12: 综合项目
- 完整的桌面应用
- 对应 Odoo: 类似开发一个完整的 Odoo 模块
快速记忆技巧
命名转换规则
| Python/Odoo | C# | 示例 |
|---|---|---|
snake_case | PascalCase(类、方法) | get_name → GetName |
snake_case | camelCase(变量) | user_name → userName |
_name | Name | 私有变量用 _name,属性用 Name |
类型对照表
| Python | C# | 备注 |
|---|---|---|
str | string | 字符串 |
int | int | 整数 |
float | double | 小数 |
bool | bool | 布尔 |
list | List<T> | 列表 |
dict | Dictionary<K,V> | 字典 |
set | HashSet<T> | 集合 |
None | null | 空值 |
常用操作对照
| 操作 | Python | C# |
|---|---|---|
| 打印 | print() | Console.WriteLine() |
| 输入 | input() | Console.ReadLine() |
| 字符串格式化 | f"{name}" | $"{name}" |
| 列表长度 | len(list) | list.Count |
| 字符串长度 | len(str) | str.Length |
| 类型转换 | int(s) | int.Parse(s) |
| 安全转换 | - | int.TryParse(s, out int n) |
记住: C# 不是更难,只是更严格。一旦习惯了静态类型,你会发现它能帮你避免很多运行时错误。
下一步
- 从 Week 1 Day 1 开始学习
- 遇到概念不清楚时,先按这个对照表找到 C# 和 Odoo 的对应关系
- 每学完一个概念,想想它在 Odoo 里的对应物
- 不要急,前两周最难,坚持过去就好了
重要提示: 不要试图用 Python 的思维写 C#。接受 C# 的方式,你会发现它的优势。