first base of project-changed apps: Herd-livestock-tag-log-elasticsearch-

This commit is contained in:
2025-05-24 15:01:55 +03:30
parent eab40af15d
commit 90a46e493c
129 changed files with 3844 additions and 187 deletions

View File

@@ -0,0 +1,32 @@
# Generated by Django 4.2.20 on 2025-05-12 11:35
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('livestock', '0002_initial'),
]
operations = [
migrations.RemoveField(
model_name='livestock',
name='type',
),
migrations.AddField(
model_name='livestock',
name='age_by_day',
field=models.IntegerField(default=0),
),
migrations.AddField(
model_name='livestock',
name='age_by_month',
field=models.IntegerField(default=0),
),
migrations.AddField(
model_name='livestock',
name='age_by_year',
field=models.IntegerField(default=0),
),
]

View File

@@ -0,0 +1,70 @@
# Generated by Django 4.2.20 on 2025-05-12 12:17
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('livestock', '0003_remove_livestock_type_livestock_age_by_day_and_more'),
]
operations = [
migrations.RemoveField(
model_name='livestock',
name='species',
),
migrations.AddField(
model_name='livestock',
name='weight_type',
field=models.CharField(choices=[('L', 'Light'), ('H', 'Heavy')], default='L', max_length=1),
),
migrations.CreateModel(
name='LiveStockUseType',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_date', models.DateTimeField(auto_now_add=True)),
('modify_date', models.DateTimeField(auto_now=True)),
('trash', models.BooleanField(default=False)),
('name', models.CharField(max_length=50)),
('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_createdby', to=settings.AUTH_USER_MODEL)),
('modified_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_modifiedby', to=settings.AUTH_USER_MODEL)),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='LiveStockType',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_date', models.DateTimeField(auto_now_add=True)),
('modify_date', models.DateTimeField(auto_now=True)),
('trash', models.BooleanField(default=False)),
('name', models.CharField(max_length=50)),
('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_createdby', to=settings.AUTH_USER_MODEL)),
('modified_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_modifiedby', to=settings.AUTH_USER_MODEL)),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='LiveStockSpecies',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_date', models.DateTimeField(auto_now_add=True)),
('modify_date', models.DateTimeField(auto_now=True)),
('trash', models.BooleanField(default=False)),
('name', models.CharField(max_length=50)),
('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_createdby', to=settings.AUTH_USER_MODEL)),
('modified_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_modifiedby', to=settings.AUTH_USER_MODEL)),
],
options={
'abstract': False,
},
),
]

View File

@@ -0,0 +1,29 @@
# Generated by Django 4.2.20 on 2025-05-12 12:28
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('livestock', '0004_remove_livestock_species_livestock_weight_type_and_more'),
]
operations = [
migrations.AddField(
model_name='livestock',
name='species',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='livestock_species', to='livestock.livestockspecies'),
),
migrations.AddField(
model_name='livestock',
name='type',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='livestock_type', to='livestock.livestocktype'),
),
migrations.AddField(
model_name='livestock',
name='use_type',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='livestock_use_type', to='livestock.livestockusetype'),
),
]

View File

@@ -0,0 +1,45 @@
# Generated by Django 4.2.20 on 2025-05-17 06:01
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('livestock', '0005_livestock_species_livestock_type_livestock_use_type'),
]
operations = [
migrations.RemoveField(
model_name='livestock',
name='created_by',
),
migrations.RemoveField(
model_name='livestock',
name='modified_by',
),
migrations.RemoveField(
model_name='livestockspecies',
name='created_by',
),
migrations.RemoveField(
model_name='livestockspecies',
name='modified_by',
),
migrations.RemoveField(
model_name='livestocktype',
name='created_by',
),
migrations.RemoveField(
model_name='livestocktype',
name='modified_by',
),
migrations.RemoveField(
model_name='livestockusetype',
name='created_by',
),
migrations.RemoveField(
model_name='livestockusetype',
name='modified_by',
),
]

View File

@@ -0,0 +1,53 @@
# Generated by Django 4.2.20 on 2025-05-17 06:24
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('livestock', '0006_remove_livestock_created_by_and_more'),
]
operations = [
migrations.AddField(
model_name='livestock',
name='created_by',
field=models.CharField(max_length=50, null=True),
),
migrations.AddField(
model_name='livestock',
name='modified_by',
field=models.CharField(max_length=50, null=True),
),
migrations.AddField(
model_name='livestockspecies',
name='created_by',
field=models.CharField(max_length=50, null=True),
),
migrations.AddField(
model_name='livestockspecies',
name='modified_by',
field=models.CharField(max_length=50, null=True),
),
migrations.AddField(
model_name='livestocktype',
name='created_by',
field=models.CharField(max_length=50, null=True),
),
migrations.AddField(
model_name='livestocktype',
name='modified_by',
field=models.CharField(max_length=50, null=True),
),
migrations.AddField(
model_name='livestockusetype',
name='created_by',
field=models.CharField(max_length=50, null=True),
),
migrations.AddField(
model_name='livestockusetype',
name='modified_by',
field=models.CharField(max_length=50, null=True),
),
]

View File

@@ -0,0 +1,45 @@
# Generated by Django 4.2.20 on 2025-05-17 06:27
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('livestock', '0007_livestock_created_by_livestock_modified_by_and_more'),
]
operations = [
migrations.RemoveField(
model_name='livestock',
name='created_by',
),
migrations.RemoveField(
model_name='livestock',
name='modified_by',
),
migrations.RemoveField(
model_name='livestockspecies',
name='created_by',
),
migrations.RemoveField(
model_name='livestockspecies',
name='modified_by',
),
migrations.RemoveField(
model_name='livestocktype',
name='created_by',
),
migrations.RemoveField(
model_name='livestocktype',
name='modified_by',
),
migrations.RemoveField(
model_name='livestockusetype',
name='created_by',
),
migrations.RemoveField(
model_name='livestockusetype',
name='modified_by',
),
]

View File

@@ -0,0 +1,56 @@
# Generated by Django 4.2.20 on 2025-05-17 06:29
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('livestock', '0008_remove_livestock_created_by_and_more'),
]
operations = [
migrations.AddField(
model_name='livestock',
name='created_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_createddby', to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='livestock',
name='modified_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_modifiedby', to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='livestockspecies',
name='created_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_createddby', to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='livestockspecies',
name='modified_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_modifiedby', to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='livestocktype',
name='created_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_createddby', to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='livestocktype',
name='modified_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_modifiedby', to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='livestockusetype',
name='created_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_createddby', to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='livestockusetype',
name='modified_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_modifiedby', to=settings.AUTH_USER_MODEL),
),
]

View File

@@ -0,0 +1,53 @@
# Generated by Django 4.2.20 on 2025-05-17 06:35
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('livestock', '0009_livestock_created_by_livestock_modified_by_and_more'),
]
operations = [
migrations.AddField(
model_name='livestock',
name='creator_info',
field=models.CharField(max_length=100, null=True),
),
migrations.AddField(
model_name='livestock',
name='modifier_info',
field=models.CharField(max_length=100, null=True),
),
migrations.AddField(
model_name='livestockspecies',
name='creator_info',
field=models.CharField(max_length=100, null=True),
),
migrations.AddField(
model_name='livestockspecies',
name='modifier_info',
field=models.CharField(max_length=100, null=True),
),
migrations.AddField(
model_name='livestocktype',
name='creator_info',
field=models.CharField(max_length=100, null=True),
),
migrations.AddField(
model_name='livestocktype',
name='modifier_info',
field=models.CharField(max_length=100, null=True),
),
migrations.AddField(
model_name='livestockusetype',
name='creator_info',
field=models.CharField(max_length=100, null=True),
),
migrations.AddField(
model_name='livestockusetype',
name='modifier_info',
field=models.CharField(max_length=100, null=True),
),
]

View File

@@ -0,0 +1,25 @@
# Generated by Django 5.0 on 2025-05-24 09:12
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('livestock', '0010_livestock_creator_info_livestock_modifier_info_and_more'),
]
operations = [
migrations.RemoveField(
model_name='livestock',
name='age_by_day',
),
migrations.RemoveField(
model_name='livestock',
name='age_by_month',
),
migrations.RemoveField(
model_name='livestock',
name='age_by_year',
),
]

View File

@@ -4,6 +4,39 @@ from apps.tag import models as tag_models
from django.db import models
class LiveStockSpecies(BaseModel): # noqa
""" species of live stocks like Kurdi, Luri, etc """ # noqa
name = models.CharField(max_length=50)
def __str__(self):
return f'{self.name}'
def save(self, *args, **kwargs):
super(LiveStockSpecies, self).save(*args, **kwargs)
class LiveStockType(BaseModel): # noqa
""" types like sheep, cow, camel, etc """
name = models.CharField(max_length=50)
def __str__(self):
return f'{self.name}'
def save(self, *args, **kwargs):
super(LiveStockType, self).save(*args, **kwargs)
class LiveStockUseType(BaseModel):
""" use types like Beef, Milky, etc """
name = models.CharField(max_length=50)
def __str__(self):
return f'{self.name}'
def save(self, *args, **kwargs):
super(LiveStockUseType, self).save(*args, **kwargs)
class LiveStock(BaseModel):
herd = models.ForeignKey(
herd_models.Herd,
@@ -17,15 +50,29 @@ class LiveStock(BaseModel):
related_name='livestock_tag',
null=True
)
types = (
type = models.ForeignKey(
LiveStockType,
on_delete=models.CASCADE,
related_name='livestock_type',
null=True
)
use_type = models.ForeignKey(
LiveStockUseType,
on_delete=models.CASCADE,
related_name='livestock_use_type',
null=True
)
weight_types = (
('L', 'Light'),
('H', 'Heavy')
)
type = models.CharField(max_length=1, choices=types)
species_type = (
()
weight_type = models.CharField(max_length=1, choices=weight_types, default='L')
species = models.ForeignKey(
LiveStockSpecies,
on_delete=models.CASCADE,
related_name='livestock_species',
null=True,
)
species = models.CharField(max_length=1, choices=species_type)
birthdate = models.DateTimeField(null=True)
gender_type = (
(1, 'male'),
@@ -34,7 +81,7 @@ class LiveStock(BaseModel):
gender = models.IntegerField(choices=gender_type, default=1)
def __str__(self):
return f'{self.get_species_display()}-{self.get_type_display()}'
return f'{self.type.name}-{self.species.name}'
def save(self, *args, **kwargs):
super(LiveStock, self).save(*args, **kwargs)

View File

@@ -1,25 +1,145 @@
from rest_framework import permissions
from apps.core import permissions
# example Code
class AuthorAllStaffAllButEditOrReadOnly(permissions.BasePermission):
edit_methods = ("PUT", "PATCH")
class LiveStockCreatePermission(permissions.BasePermission):
""" permission to create livestock """
def has_permission(self, request, view):
if request.user.is_authenticated:
user_level_info = self.get_user_permissions(request, view)
if 'live_stock_create' in user_level_info['permissions']:
return True
def has_object_permission(self, request, view, obj):
if request.user.is_superuser:
class LiveStockUpdatePermission(permissions.BasePermission):
""" permission to update livestock """
def has_permission(self, request, view):
user_level_info = self.get_user_permissions(request, view)
if 'live_stock_update' in user_level_info['permissions']:
return True
if request.method in permissions.SAFE_METHODS:
class LiveStockTrashPermission(permissions.BasePermission):
""" permission to trash livestock """
def has_permission(self, request, view):
user_level_info = self.get_user_permissions(request, view)
if 'live_stock_trash' in user_level_info['permissions']:
return True
if obj.author == request.user:
class LiveStockDeletePermission(permissions.BasePermission):
""" permission to Delete livestock """
def has_permission(self, request, view):
user_level_info = self.get_user_permissions(request, view)
if 'live_stock_delete' in user_level_info['permissions']:
return True
if request.user.is_staff and request.method not in self.edit_methods:
class StockTypeCreatePermission(permissions.BasePermission):
""" permission to create livestock type """
def has_permission(self, request, view):
user_level_info = self.get_user_permissions(request, view)
if 'stock_type_create' in user_level_info['permissions']:
return True
return False
class StockTypeUpdatePermission(permissions.BasePermission):
""" permission to update livestock type """
def has_permission(self, request, view):
user_level_info = self.get_user_permissions(request, view)
if 'stock_type_update' in user_level_info['permissions']:
return True
class StockTypeTrashPermission(permissions.BasePermission):
""" permission to trash livestock type """
def has_permission(self, request, view):
user_level_info = self.get_user_permissions(request, view)
if 'stock_type_trash' in user_level_info['permissions']:
return True
class StockTypeDeletePermission(permissions.BasePermission):
""" permission to delete livestock type """
def has_permission(self, request, view):
user_level_info = self.get_user_permissions(request, view)
if 'stock_type_delete' in user_level_info['permissions']:
return True
class StockUseTypeCreatePermission(permissions.BasePermission):
""" permission to create livestock use type """
def has_permission(self, request, view):
user_level_info = self.get_user_permissions(request, view)
if 'stock_use_type_create' in user_level_info['permissions']:
return True
class StockUseTypeUpdatePermission(permissions.BasePermission):
""" permission to update livestock use type """
def has_permission(self, request, view):
user_level_info = self.get_user_permissions(request, view)
if 'stock_use_type_update' in user_level_info['permissions']:
return True
class StockUseTypeTrashPermission(permissions.BasePermission):
""" permission to trash livestock use type """
def has_permission(self, request, view):
user_level_info = self.get_user_permissions(request, view)
if 'stock_use_type_trash' in user_level_info['permissions']:
return True
class StockUseTypeDeletePermission(permissions.BasePermission):
""" permission to delete livestock use type """
def has_permission(self, request, view):
user_level_info = self.get_user_permissions(request, view)
if 'stock_use_type_delete' in user_level_info['permissions']:
return True
class StockSpeciesCreatePermission(permissions.BasePermission):
""" permission to create livestock species """
def has_permission(self, request, view):
user_level_info = self.get_user_permissions(request, view)
if 'stock_species_create' in user_level_info['permissions']:
return True
class StockSpeciesUpdatePermission(permissions.BasePermission):
""" permission to update livestock species """
def has_permission(self, request, view):
user_level_info = self.get_user_permissions(request, view)
if 'stock_species_update' in user_level_info['permissions']:
return True
class StockSpeciesTrashPermission(permissions.BasePermission):
""" permission to trash livestock species """
def has_permission(self, request, view):
user_level_info = self.get_user_permissions(request, view)
if 'stock_species_trash' in user_level_info['permissions']:
return True
class StockSpeciesDeletePermission(permissions.BasePermission):
""" permission to delete livestock species """
def has_permission(self, request, view):
user_level_info = self.get_user_permissions(request, view)
if 'stock_species_delete' in user_level_info['permissions']:
return True

View File

@@ -1 +1,8 @@
# Your urls go here
from django.urls import path, include
urlpatterns = [
path('web/api/', include('apps.livestock.web.api.v1.urls')),
# path('app/api/', include('apps.livestock.mobile.api.v1.urls')),
# path('pos/api/', include('apps.livestock.pos.api.v1.urls'))
]

View File

@@ -0,0 +1,166 @@
from rest_framework import viewsets
from apps.livestock import models as livestock_models
from . import serializers as livestock_serializers
from rest_framework.exceptions import APIException
from rest_framework.decorators import action
from rest_framework.response import Response
from django.db import transaction
from rest_framework import status
def trash(queryset, pk):
""" sent object to trash """
obj = queryset.get(id=pk)
obj.trash = True
obj.save()
def delete(queryset, pk):
""" full delete object """
obj = queryset.get(id=pk)
obj.delete()
class LiveStockViewSet(viewsets.ModelViewSet):
queryset = livestock_models.LiveStock.objects.all()
serializer_class = livestock_serializers.LiveStockSerializer
@action(
methods=['put'],
detail=True,
url_path='trash',
url_name='trash',
name='trash',
)
@transaction.atomic
def trash(self, request, pk=None):
""" Sent livestock to trash """
try:
trash(self.queryset, pk)
except APIException as e:
return Response(e, status.HTTP_204_NO_CONTENT)
@action(
methods=['post'],
detail=True,
url_name='delete',
url_path='delete',
name='delete'
)
@transaction.atomic
def delete(self, request, pk=None):
""" Full delete of livestock object """
try:
delete(self.queryset, pk)
return Response(status=status.HTTP_200_OK)
except APIException as e:
return Response(e, status=status.HTTP_204_NO_CONTENT)
class LiveStockTypeViewSet(viewsets.ModelViewSet):
queryset = livestock_models.LiveStockType.objects.all()
serializer_class = livestock_serializers.LiveStockTypeSerializer
@action(
methods=['put'],
detail=True,
url_path='trash',
url_name='trash',
name='trash',
)
@transaction.atomic
def trash(self, request, pk=None):
""" Sent livestock type to trash """
try:
trash(self.queryset, pk)
except APIException as e:
return Response(e, status.HTTP_204_NO_CONTENT)
@action(
methods=['post'],
detail=True,
url_name='delete',
url_path='delete',
name='delete'
)
@transaction.atomic
def delete(self, request, pk=None):
""" Full delete of livestock type object """
try:
delete(self.queryset, pk)
return Response(status=status.HTTP_200_OK)
except APIException as e:
return Response(e, status=status.HTTP_204_NO_CONTENT)
class LiveStockUseTypeViewSet(viewsets.ModelViewSet):
queryset = livestock_models.LiveStockUseType.objects.all()
serializer_class = livestock_serializers.LiveStockUseTypeSerializer
@action(
methods=['put'],
detail=True,
url_path='trash',
url_name='trash',
name='trash',
)
@transaction.atomic
def trash(self, request, pk=None):
""" Sent livestock use type to trash """
try:
trash(self.queryset, pk)
except APIException as e:
return Response(e, status.HTTP_204_NO_CONTENT)
@action(
methods=['post'],
detail=True,
url_name='delete',
url_path='delete',
name='delete'
)
@transaction.atomic
def delete(self, request, pk=None):
""" Full delete of livestock use type object """
try:
delete(self.queryset, pk)
return Response(status=status.HTTP_200_OK)
except APIException as e:
return Response(e, status=status.HTTP_204_NO_CONTENT)
class LiveStockSpeciesViewSet(viewsets.ModelViewSet):
queryset = livestock_models.LiveStockSpecies.objects.all()
serializer_class = livestock_serializers.LiveStockSpeciesSerializer
@action(
methods=['put'],
detail=True,
url_path='trash',
url_name='trash',
name='trash',
)
@transaction.atomic
def trash(self, request, pk=None):
""" Sent species to trash """
try:
trash(self.queryset, pk)
return Response(status=status.HTTP_200_OK)
except APIException as e:
return Response
@action(
methods=['post'],
detail=True,
url_name='delete',
url_path='delete',
name='delete'
)
@transaction.atomic
def delete(self, request, pk=None):
""" Full delete of species object """
try:
delete(self.queryset, pk)
return Response(status=status.HTTP_200_OK)
except APIException as e:
return Response(e, status=status.HTTP_204_NO_CONTENT)

View File

@@ -0,0 +1,62 @@
from rest_framework import serializers
from apps.livestock import models as livestock_models
from apps.herd.web.api.v1.serializers import HerdSerializer
from apps.tag.web.api.v1.serializers import TagSerializer
class LiveStockTypeSerializer(serializers.ModelSerializer):
class Meta:
model = livestock_models.LiveStockType
fields = [
'id',
'name'
]
class LiveStockUseTypeSerializer(serializers.ModelSerializer):
class Meta:
model = livestock_models.LiveStockUseType
fields = [
'id',
'name'
]
class LiveStockSpeciesSerializer(serializers.ModelSerializer):
class Meta:
model = livestock_models.LiveStockSpecies
fields = [
'id',
'name'
]
class LiveStockSerializer(serializers.ModelSerializer):
""" livestock serializer """
class Meta:
model = livestock_models.LiveStock
fields = [
'id',
'herd',
'tag',
'type',
'use_type',
'weight_type',
'species',
'birthdate',
'gender',
]
depth = 1
def to_representation(self, instance):
""" Customize output of serializer """
representation = super().to_representation(instance)
if isinstance(instance, livestock_models.LiveStock):
representation['herd'] = HerdSerializer(instance.herd).data
representation['tag'] = TagSerializer(instance.tag).data
representation['type'] = LiveStockTypeSerializer(instance.type).data
representation['use_type'] = LiveStockUseTypeSerializer(instance.use_type).data
representation['species'] = LiveStockSpeciesSerializer(instance.species).data
return representation

View File

@@ -0,0 +1,18 @@
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .api import (
LiveStockViewSet,
LiveStockTypeViewSet,
LiveStockSpeciesViewSet,
LiveStockUseTypeViewSet
)
router = DefaultRouter()
router.register(r'livestock', LiveStockViewSet, basename='livestock')
router.register(r'livestock_type', LiveStockTypeViewSet, basename='livestock_type')
router.register(r'livestock_use_type', LiveStockUseTypeViewSet, basename='livestock_use_type')
router.register(r'livestock_species', LiveStockSpeciesViewSet, basename='livestock_species')
urlpatterns = [
path('v1/', include(router.urls))
]