Documentation Index Fetch the complete documentation index at: https://mintlify.com/allegro/ralph/llms.txt
Use this file to discover all available pages before exploring further.
Common questions and solutions for Ralph developers.
Admin and Views
Why do I get 'ImproperlyConfigured' error after attaching an extra view to admin class?
How do I see asset boxes in front dashboard?
By default, the front dashboard doesn’t show “Hardware loan”, “Hardware release”, or “Hardware return” boxes. These boxes appear only when you have assigned assets in specific states. Requirements:
Asset must be in ‘in progress’ or ‘in use’ state
Asset must be assigned to the current user
Transition IDs must be configured in settings
Setup steps for empty database:
Create the database and superuser:
dev_ralph migrate
make menu
dev_ralph createsuperuser --email= 'admin@example.com' --username=root
dev_ralph createsuperuser --email= 'user@example.com' --username=r2
Create a transition:
Navigate to: http://localhost:8000/transitions/transitionmodel/1/
Click [add another transition]
Set:
Source: ‘in progress’
Destination: ‘in use’
Click [Save]
Find the transition ID:
SELECT * FROM transitions_transition;
Note the id value (e.g., 1)
Configure settings:
Add to settings/dev.py:
ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG [ 'RETURN_TRANSITION_ID' ] = 1
ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG [ 'LOAN_TRANSITION_ID' ] = 1
ACCEPT_ASSETS_FOR_CURRENT_USER_CONFIG [ 'TRANSITION_ID' ] = 1
Replace 1 with your actual transition ID.
Create test assets:
Navigate to http://localhost:8000/back_office/backofficeasset/add/ and create assets with:
Status: ‘in progress’
Assigned to user: r2
Owner: r2
Repeat with statuses ‘return in progress’ and ‘loan in progress’.
View dashboard:
Open incognito mode and login as user r2 to see the dashboard boxes.
Why do I get 'NoReverseMatch' error for transition_bulk?
This error occurs when transition IDs are not properly configured: NoReverseMatch at /
Reverse for 'back_office_backofficeasset_transition_bulk' with arguments '(None,)' and keyword arguments '{}' not found.
Solution:
Configure the transition IDs in your settings file as shown in the previous FAQ item.
API Development
How do I create a new API endpoint?
Create API endpoints using Ralph’s base classes: from ralph.api import RalphAPISerializer, RalphAPIViewSet, router
class MyModelSerializer ( RalphAPISerializer ):
class Meta :
model = MyModel
fields = '__all__' # or specify fields explicitly
class MyModelViewSet ( RalphAPIViewSet ):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
filterset_fields = [ 'name' , 'status' ]
router.register( r 'my-models' , MyModelViewSet)
The endpoint will be available at /api/my-models/. See API Documentation for advanced features.
How do I optimize API queries to avoid N+1 problems?
Use select_related and prefetch_related in your ViewSet: class MyModelViewSet ( RalphAPIViewSet ):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
# Use select_related for ForeignKey and OneToOne
select_related = [
'owner' ,
'category' ,
'service_env__service' ,
]
# Use prefetch_related for ManyToMany and reverse ForeignKey
prefetch_related = [
'tags' ,
'licences' ,
'ethernet_set' ,
]
Tip: Check the Django Debug Toolbar or use django.db.connection.queries to identify N+1 queries.
How do I add custom filtering to an API endpoint?
Ralph provides multiple filtering options: 1. Simple field filtering: class MyModelViewSet ( RalphAPIViewSet ):
filterset_fields = [ 'name' , 'status' , 'created_date' ]
Usage: /api/my-models/?name=test&status=active 2. Lookup filtering (automatic):
Usage: /api/my-models/?name__startswith=test&created_date__gte=2024-01-013. Extended filters for polymorphic models: class MyModelViewSet ( RalphAPIViewSet ):
extended_filter_fields = {
'name' : [ 'asset__hostname' , 'virtual__name' , 'cloud__hostname' ]
}
Usage: /api/my-models/?name=test searches all specified fields 4. Custom filter backend: from django_filters import rest_framework as filters
class MyModelFilter ( filters . FilterSet ):
min_price = filters.NumberFilter( field_name = 'price' , lookup_expr = 'gte' )
max_price = filters.NumberFilter( field_name = 'price' , lookup_expr = 'lte' )
class Meta :
model = MyModel
fields = [ 'name' , 'status' ]
class MyModelViewSet ( RalphAPIViewSet ):
filterset_class = MyModelFilter
How do I implement separate serializers for read and write operations?
Use the save_serializer_class attribute: class MyModelSerializer ( RalphAPISerializer ):
# Read serializer with nested objects
owner = UserSerializer()
category = CategorySerializer()
class Meta :
model = MyModel
fields = '__all__'
class MyModelSaveSerializer ( RalphAPISaveSerializer ):
# Write serializer with IDs only
class Meta :
model = MyModel
fields = '__all__'
class MyModelViewSet ( RalphAPIViewSet ):
serializer_class = MyModelSerializer
save_serializer_class = MyModelSaveSerializer
Now:
GET requests return nested objects
POST/PUT/PATCH requests accept IDs
Models and Database
How do I add custom validation to a model?
Override the clean() method: from django.core.exceptions import ValidationError
from django.db import models
class MyModel ( models . Model ):
start_date = models.DateField()
end_date = models.DateField()
def clean ( self ):
super ().clean()
if self .end_date and self .start_date > self .end_date:
raise ValidationError({
'end_date' : 'End date must be after start date'
})
This validation will run:
In Django admin forms
In API requests (if using RalphAPISerializer)
When calling full_clean() or save() with validation
How do I create database migrations?
After modifying models: # Create migration
dev_ralph makemigrations
# Review the migration file
cat src/ralph/myapp/migrations/0XXX_auto_YYYYMMDD_HHMM.py
# Apply migration
dev_ralph migrate
# Check migration status
dev_ralph showmigrations
Best practices:
Review generated migrations before committing
Add data migrations for complex changes
Test migrations on a copy of production data
Never modify applied migrations
How do I use custom fields?
Ralph supports custom fields through the Custom Fields framework:
Enable custom fields in admin:
from ralph.lib.custom_fields.admin import CustomFieldsAdminMixin
@register (MyModel)
class MyAdmin ( CustomFieldsAdminMixin , RalphAdmin ):
pass
Custom fields are automatically available in API
Access in code:
obj = MyModel.objects.get( id = 1 )
value = obj.custom_fields.get( 'my_custom_field' )
obj.custom_fields[ 'my_custom_field' ] = 'new value'
obj.save()
See Custom Fields Documentation for details.
Testing
# Run all tests
make test
# Run tests for specific app
make test TEST=ralph.assets
# Run specific test class
test_ralph test ralph.assets.tests.test_models.AssetTest
# Run specific test method
test_ralph test ralph.assets.tests.test_models.AssetTest.test_create_asset
# Run with coverage
make coverage
# Keep database between test runs (faster)
test_ralph test ralph.assets --keepdb
How do I write API tests?
Use Ralph’s test utilities: from ralph.api.tests import RalphAPITestCase
from ralph.myapp.models import MyModel
class MyModelAPITest ( RalphAPITestCase ):
def setUp ( self ):
super ().setUp()
self .obj = MyModel.objects.create( name = 'Test' )
def test_list_endpoint ( self ):
url = reverse( 'mymodel-list' )
response = self .client.get(url)
self .assertEqual(response.status_code, 200 )
self .assertEqual( len (response.data[ 'results' ]), 1 )
def test_create_endpoint ( self ):
url = reverse( 'mymodel-list' )
data = { 'name' : 'New Object' }
response = self .client.post(url, data, format = 'json' )
self .assertEqual(response.status_code, 201 )
self .assertEqual(MyModel.objects.count(), 2 )
How do I use factories for test data?
Ralph uses factory_boy for test data: import factory
from factory.django import DjangoModelFactory
class MyModelFactory ( DjangoModelFactory ):
name = factory.Sequence( lambda n : f 'Object { n } ' )
status = 'active'
created_date = factory.Faker( 'date_this_year' )
class Meta :
model = MyModel
# Use in tests
class MyTest ( TestCase ):
def test_something ( self ):
obj = MyModelFactory()
objects = MyModelFactory.create_batch( 5 )
Deployment and Configuration
How do I configure Ralph settings?
How do I enable debug mode safely?
Never enable DEBUG in production! For development: # settings/local.py
DEBUG = True
ALLOWED_HOSTS = [ 'localhost' , '127.0.0.1' ]
# Install debug toolbar
INSTALLED_APPS += [ 'debug_toolbar' ]
MIDDLEWARE += [ 'debug_toolbar.middleware.DebugToolbarMiddleware' ]
INTERNAL_IPS = [ '127.0.0.1' ]
For production debugging:
Use logging instead of DEBUG=True
Configure Sentry or similar error tracking
Use Django’s logging framework
Configure in settings: LOGGING = {
'version' : 1 ,
'disable_existing_loggers' : False ,
'formatters' : {
'verbose' : {
'format' : ' {levelname} {asctime} {module} {message} ' ,
'style' : '{' ,
},
},
'handlers' : {
'file' : {
'level' : 'INFO' ,
'class' : 'logging.FileHandler' ,
'filename' : '/var/log/ralph/ralph.log' ,
'formatter' : 'verbose' ,
},
},
'loggers' : {
'ralph' : {
'handlers' : [ 'file' ],
'level' : 'INFO' ,
'propagate' : True ,
},
},
}
Use in code: import logging
logger = logging.getLogger( __name__ )
logger.info( 'Operation completed' )
logger.warning( 'Unusual condition' )
logger.error( 'Error occurred' , exc_info = True )
How do I profile slow queries?
Using Django Debug Toolbar: # settings/dev.py
INSTALLED_APPS += [ 'debug_toolbar' ]
MIDDLEWARE += [ 'debug_toolbar.middleware.DebugToolbarMiddleware' ]
Using query logging: from django.db import connection, reset_queries
from django.conf import settings
settings. DEBUG = True
reset_queries()
# Your code here
MyModel.objects.select_related( 'owner' ).all()
print ( f "Total queries: { len (connection.queries) } " )
for query in connection.queries:
print ( f " { query[ 'time' ] } : { query[ 'sql' ] } " )
Using django-silk: Add to settings and visit /silk/ for profiling UI.
How do I optimize large querysets?
Use pagination: from django.core.paginator import Paginator
queryset = MyModel.objects.all()
paginator = Paginator(queryset, 100 ) # 100 per page
page = paginator.get_page( 1 )
Use iterator for large datasets: for obj in MyModel.objects.iterator( chunk_size = 1000 ):
process(obj)
Use only() and defer(): # Only load specific fields
MyModel.objects.only( 'id' , 'name' )
# Defer large fields
MyModel.objects.defer( 'description' , 'content' )
Use values() for simple data: # Returns dicts instead of model instances
MyModel.objects.values( 'id' , 'name' , 'status' )
Need More Help?
If your question isn’t answered here: