USER
File "/usr/local/lib/python3.10/site-packages/click_odoo_contrib/update.py", line 299, in OdooEnvironmentWithUpdate
_update_db(
File "/usr/local/lib/python3.10/site-packages/click_odoo_contrib/update.py", line 270, in _update_db
_update_db_nolock(
File "/usr/local/lib/python3.10/site-packages/click_odoo_contrib/update.py", line 248, in _update_db_nolock
odoo.modules.registry.Registry.new(database, update_module=True)
File "/usr/local/lib/python3.10/site-packages/decorator.py", line 232, in fun
return caller(func, *(extras + args), **kw)
File "/odoo/src/odoo/tools/func.py", line 87, in locked
return func(inst, *args, **kwargs)
File "/odoo/src/odoo/modules/registry.py", line 114, in new
odoo.modules.load_modules(registry, force_demo, status, update_module)
File "/odoo/src/odoo/modules/loading.py", line 536, in load_modules
env['ir.model.data']._process_end(processed_modules)
File "/odoo/src/odoo/addons/base/models/ir_model.py", line 2579, in _process_end
self._process_end_unlink_record(record)
File "/odoo/src/odoo/addons/base/models/ir_model.py", line 2508, in _process_end_unlink_record
record.unlink()
File "/odoo/src/odoo/addons/base/models/res_users.py", line 1492, in unlink
res = super(GroupsView, self).unlink()
File "/odoo/src/odoo/models.py", line 4244, in unlink
cr.execute(SQL(
File "/odoo/src/odoo/sql_db.py", line 332, in execute
res = self._obj.execute(query, params)
psycopg2.errors.ForeignKeyViolation: update or delete on table "res_groups" violates foreign key constraint "ir_model_access_group_id_fkey" on table "ir_model_access"
DETAIL: Key (id)=(94) is still referenced from table "ir_model_access".
Error: update or delete on table "res_groups" violates foreign key constraint "ir_model_access_group_id_fkey" on table "ir_model_access"
DETAIL: Key (id)=(94) is still referenced from table "ir_model_access".
from odoo import fields, models, api
from odoo.exceptions import AccessError
class Users(models.Model):
_inherit = "res.users"
position = fields.Char(string='Position')
type = fields.Selection([
('admin', 'Admin'),
('moderator', 'Moderator'),
('reader', 'Reader'),
], string='User Type', required=True, default='reader')
role = fields.Selection([
('republic', 'Republic'),
('region', 'Region'),
('district', 'District'),
('mahalla', 'Mahalla'),
], string='Role', default='mahalla')
region_id = fields.Many2one('region', string="Region")
district_id = fields.Many2one('district', string="District")
mahalla_id = fields.Many2one('mahalla', string="Mahalla")
@api.onchange('type')
def _onchange_type(self):
if self.type == 'admin':
self.role = False
self.region_id = False
self.district_id = False
self.mahalla_id = False
self._update_role_visibility()
@api.onchange('role')
def _onchange_role(self):
if self.type != 'admin':
self._update_role_visibility()
def _update_role_visibility(self):
if self.type == 'admin':
pass
elif self.role == 'republic':
pass
elif self.role == 'region':
self.district_id = False
self.mahalla_id = False
elif self.role == 'district':
self.mahalla_id = False
elif self.role == 'mahalla':
pass
def action_change_password(self):
self.ensure_one()
return {
'type': 'ir.actions.act_window',
'res_model': 'change.password.wizard',
'view_mode': 'form',
'view_id': self.env.ref('base.change_password_wizard_view').id,
'target': 'new',
'context': {'default_user_id': self.id},
}
def assign_group_based_on_role(self):
self.ensure_one()
admin_group = self.env.ref('mahallam.group_admin')
group_republic = self.env.ref('mahallam.group_republic')
group_region = self.env.ref('mahallam.group_region')
group_district = self.env.ref('mahallam.group_district')
group_mahalla = self.env.ref('mahallam.group_mahalla')
group_mahalla = self.env.ref('mahallam.group_mahalla')
group_reader = self.env.ref('mahallam.group_reader')
group_moderator = self.env.ref('mahallam.group_moderator')
group_hierarchical = self.env.ref('mahallam.group_hierarchical')
group_localization = self.env.ref('mahallam.group_localization')
group_application = self.env.ref('mahallam.group_application')
group_announcement = self.env.ref('mahallam.group_announcement')
group_notification = self.env.ref('mahallam.group_notification')
group_questionnaire = self.env.ref('mahallam.group_questionnaire')
group_user_questionnaire = self.env.ref('mahallam.group_user_questionnaire')
group_system = self.env.ref('mahallam.group_system')
group_user = self.env.ref('mahallam.group_user')
self.groups_id = [
(3, admin_group.id), (3, group_republic.id), (3, group_region.id),
(3, group_district.id), (3, group_mahalla.id),
(3, group_reader.id), (3, group_moderator.id),
(3, group_hierarchical.id), (3, group_localization.id),
(3, group_application.id), (3, group_announcement.id),
(3, group_notification.id), (3, group_questionnaire.id),
(3, group_user_questionnaire.id),
]
if self.type == 'moderator':
self.groups_id = [(4, group_moderator.id)]
elif self.role == 'republic':
self.groups_id = [(4, group_republic.id)]
elif self.role == 'region':
self.groups_id = [(4, group_region.id), (4, group_localization.id), (4, group_hierarchical.id)]
elif self.role == 'district':
self.groups_id = [(4, group_district.id), (4, group_localization.id), (4, group_hierarchical.id)]
elif self.role == 'mahalla':
self.groups_id = [(4, group_mahalla.id), (4, group_localization.id), (4, group_hierarchical.id)]
elif self.type == 'reader':
self.groups_id = [(4, group_reader.id)]
@api.model
def create(self, vals):
user = super(Users, self).create(vals)
user.assign_group_based_on_role()
return user
def write(self, vals):
res = super(Users, self).write(vals)
if 'type' in vals or 'role' in vals:
self.assign_group_based_on_role()
return res
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<data noupdate="1">
<record id="mahallam.group_admin" model="res.groups">
<field name="name">Group admin</field>
<field name="category_id" ref="base.module_category_hidden"/>
</record>
<record id="mahallam.group_republic" model="res.groups">
<field name="name">Group republic</field>
<field name="category_id" ref="base.module_category_hidden"/>
</record>
<record id="mahallam.group_region" model="res.groups">
<field name="name">Group region</field>
<field name="category_id" ref="base.module_category_hidden"/>
</record>
<record id="mahallam.group_district" model="res.groups">
<field name="name">Group district</field>
<field name="category_id" ref="base.module_category_hidden"/>
</record>
<record id="mahallam.group_mahalla" model="res.groups">
<field name="name">Group mahalla</field>
<field name="category_id" ref="base.module_category_hidden"/>
</record>
<record id="mahallam.group_reader" model="res.groups">
<field name="name">Group reader</field>
<field name="category_id" ref="base.module_category_hidden"/>
</record>
<record id="mahallam.group_moderator" model="res.groups">
<field name="name">Group moderator</field>
<field name="category_id" ref="base.module_category_hidden"/>
</record>
<record id="mahallam.group_hierarchical" model="res.groups">
<field name="name">Group hierarchical</field>
<field name="category_id" ref="base.module_category_hidden"/>
</record>
<record id="mahallam.group_localization" model="res.groups">
<field name="name">Group localization</field>
<field name="category_id" ref="base.module_category_hidden"/>
</record>
<record id="mahallam.group_application" model="res.groups">
<field name="name">Group application</field>
<field name="category_id" ref="base.module_category_hidden"/>
</record>
<record id="mahallam.group_announcement" model="res.groups">
<field name="name">Group announcement</field>
<field name="category_id" ref="base.module_category_hidden"/>
</record>
<record id="mahallam.group_notification" model="res.groups">
<field name="name">Group notification</field>
<field name="category_id" ref="base.module_category_hidden"/>
</record>
<record id="mahallam.group_questionnaire" model="res.groups">
<field name="name">Group questionnaire</field>
<field name="category_id" ref="base.module_category_hidden"/>
</record>
<record id="mahallam.group_user_questionnaire" model="res.groups">
<field name="name">Group user questionnaire</field>
<field name="category_id" ref="base.module_category_hidden"/>
</record>
<record id="base.group_system" model="res.groups">
<field name="name">Group system</field>
<field name="category_id" ref="base.module_category_hidden"/>
</record>
<record id="base.group_user" model="res.groups">
<field name="name">Group user</field>
<field name="category_id" ref="base.module_category_hidden"/>
</record>
</data>
</odoo>ASSISTANT
The error you’re encountering occurs because Odoo is attempting to update or delete a group (`res_groups` with `id=94`) that is still being referenced by records in the `ir_model_access` table. This violates the foreign key constraint, preventing the operation. Here's a detailed breakdown of the issue and steps to resolve it:
### **Understanding the Error**
- **Error Message:**
```
psycopg2.errors.ForeignKeyViolation: update or delete on table "res_groups" violates foreign key constraint "ir_model_access_group_id_fkey" on table "ir_model_access"
DETAIL: Key (id)=(94) is still referenced from table "ir_model_access".
```
- **Cause:**
- The group with `id=94` in the `res_groups` table is still being referenced in the `ir_model_access` table.
- When Odoo tries to update or delete this group, PostgreSQL prevents it to maintain referential integrity.
### **Steps to Resolve**
1. **Identify the Problematic Group:**
- Determine which group corresponds to `id=94`. You can do this by querying the database or checking your module's XML records.
```sql
SELECT id, name FROM res_groups WHERE id = 94;
```
- Alternatively, in Odoo's shell or via UI, find the group by external ID if available.
2. **Check References in `ir_model_access`:**
- Find all access records that reference this group.
```sql
SELECT * FROM ir_model_access WHERE group_id = 94;
```
- This will show you which access controls are linked to the group.
3. **Decide on Action:**
- **If the Group Should Not Be Deleted:**
- Ensure that your code or XML isn’t attempting to delete or modify this group inadvertently.
- **If the Group Should Be Deleted:**
- You must first remove or update all `ir_model_access` records that reference this group.
4. **Updating Access Rights:**
- **Option 1: Remove References**
- If the group is no longer needed, delete the related access records.
```sql
DELETE FROM ir_model_access WHERE group_id = 94;
```
- **Option 2: Reassign Access Rights**
- If the access rights should be retained under a different group, update the `group_id` accordingly.
```sql
UPDATE ir_model_access SET group_id = <new_group_id> WHERE group_id = 94;
```
5. **Review Your Module’s Code and XML:**
- **Python Code:**
- Ensure that when you assign or unassign groups in your `assign_group_based_on_role` method, you’re not unintentionally removing essential groups.
- For example, avoid unassigning system-critical groups like `base.group_user` or `base.group_system`.
```python
self.groups_id = [
(3, admin_group.id), (3, group_republic.id),
# ... other groups
(3, group_user.id), # Avoid removing essential groups
]
```
- **XML Definitions:**
- Ensure that groups are correctly defined with unique external IDs and aren’t duplicated or conflicting.
- Verify that the groups you’re referring to in your Python code match those defined in your XML.
```xml
<record id="mahallam.group_admin" model="res.groups">
<field name="name">Group Admin</field>
<field name="category_id" ref="base.module_category_hidden"/>
</record>
```
6. **Update the Module Safely:**
- After making the necessary changes, update your module.
- **Using Odoo CLI:**
```bash
odoo -u your_module_name -d your_database_name
```
- **Using Odoo UI:**
- Go to **Apps**.
- Update the module list.
- Locate your module and click **Update**.
7. **Ensure Data Integrity:**
- After updating, verify that:
- All necessary groups are present.
- Access rights are correctly assigned.
- No other foreign key violations occur.
### **Best Practices to Prevent Similar Issues**
- **Avoid Deleting Groups Directly:**
- Instead of deleting groups, consider deactivating them or changing their assignments.
- **Consistent Group Management:**
- Manage groups consistently through XML or code to prevent discrepancies between the database and your module definitions.
- **Backup Before Major Changes:**
- Always backup your database before performing operations that modify groups or access rights.
- **Use Odoo’s Access Control Mechanisms Properly:**
- Ensure that when you define access controls (`ir_model_access`), they reference the correct and existing groups.
### **Example Correction in Your Code**
If the `assign_group_based_on_role` method is removing essential groups or unintentionally removing groups that are still in use, adjust it as follows:
```python
def assign_group_based_on_role(self):
self.ensure_one()
# Define group references
admin_group = self.env.ref('mahallam.group_admin')
group_republic = self.env.ref('mahallam.group_republic')
group_region = self.env.ref('mahallam.group_region')
group_district = self.env.ref('mahallam.group_district')
group_mahalla = self.env.ref('mahallam.group_mahalla')
group_reader = self.env.ref('mahallam.group_reader')
group_moderator = self.env.ref('mahallam.group_moderator')
group_hierarchical = self.env.ref('mahallam.group_hierarchical')
group_localization = self.env.ref('mahallam.group_localization')
group_application = self.env.ref('mahallam.group_application')
group_announcement = self.env.ref('mahallam.group_announcement')
group_notification = self.env.ref('mahallam.group_notification')
group_questionnaire = self.env.ref('mahallam.group_questionnaire')
group_user_questionnaire = self.env.ref('mahallam.group_user_questionnaire')
# Remove specific groups without affecting system groups
self.groups_id = [
(3, admin_group.id),
(3, group_republic.id),
(3, group_region.id),
(3, group_district.id),
(3, group_mahalla.id),
(3, group_reader.id),
(3, group_moderator.id),
(3, group_hierarchical.id),
(3, group_localization.id),
(3, group_application.id),
(3, group_announcement.id),
(3, group_notification.id),
(3, group_questionnaire.id),
(3, group_user_questionnaire.id),
]
# Assign groups based on role
if self.type == 'moderator':
self.groups_id += [(4, group_moderator.id)]
elif self.role == 'republic':
self.groups_id += [(4, group_republic.id)]
elif self.role == 'region':
self.groups_id += [(4, group_region.id), (4, group_localization.id), (4, group_hierarchical.id)]
elif self.role == 'district':
self.groups_id += [(4, group_district.id), (4, group_localization.id), (4, group_hierarchical.id)]
elif self.role == 'mahalla':
self.groups_id += [(4, group_mahalla.id), (4, group_localization.id), (4, group_hierarchical.id)]
elif self.type == 'reader':
self.groups_id += [(4, group_reader.id)]
```
**Key Changes:**
- **Avoid Duplicating Group Assignments:**
- Use `+=` to append group assignments instead of overwriting.
- **Preserve Essential Groups:**
- Ensure that critical groups like `base.group_user` remain assigned unless intentionally modified.
### **Final Checks**
After implementing the above steps:
1. **Restart Odoo Server:**
- Ensure all changes are loaded properly.
```bash
sudo systemctl restart odoo
```
2. **Test Functionality:**
- Verify that users are assigned to the correct groups based on their roles.
- Ensure that no access rights are broken and that the system functions as expected.
3. **Monitor Logs:**
- Keep an eye on Odoo’s logs to catch any further issues early.
### **Conclusion**
The foreign key violation you're experiencing is due to lingering references in `ir_model_access` to a group you're trying to update or delete. By identifying and managing these references appropriately, and ensuring your module’s code correctly handles group assignments without inadvertently removing essential groups, you can resolve this error and maintain the integrity of your Odoo system.
If you continue to face issues or need further assistance, please provide additional context or specifics about the group with `id=94` and how it's being used in your modules.