django Autocomplete-light how to choose a specific method from a mode - django-autocomplete-light

I am new at django and autocomplete-light. I try to get a different fields of the model from autocomplete-light, but it always return the same field. And the reason is because def in the Model defined one field. So I created another def, but can not make autocomplete-light to call that specific def. Here is my code.
models.py:
class Item(models.Model):
...
serial_number=models.CharField(max_length=100, unique=True)
barcode=models.CharField(max_length=25, unique=True)
def __unicode__(self):
return self.serial_number
def bar(self):
return self.barcode
.......
autocomplete_light_registry.py
autocomplete_light.register(Item,
name='AutocompleteItemserial',
search_fields=['serial_number'],
)
autocomplete_light.register(Item,
name='AutocompleteItembarcode',
search_fields=['barcode'],
)
Here is the issue: when I try to get the barcodes from the autocomplete-light, it returns serial_numbers. No matter what I try to get from the Item model, it always returns the serial number. I really appreciate for the answers. Thank you.
Just in case, here is the form.py
forms.py
class ItemForm(forms.ModelForm):
widgets = {
'serial_number': autocomplete_light.TextWidget('AutocompleteItemserial'),
'barcode': autocomplete_light.TextWidget('AutocompleteItembarcode'),
}

Although this is an old post but as I just faced the same issue therefore I am sharing my solution.
The reason autocomplete is returning serial_number is because django-autocomplete-light uses the __unicode__ method of the model to show the results. In your AutocompleteItembarcode all that is being done is autocomplete-light is searching by barcode field of Item.
Try the following.
In app/autocomplete_light_registry.py
from django.utils.encoding import force_text
class ItemAutocomplete(autocomplete_light.AutocompleteModelBase):
search_fields = ['serial_number']
model = Item
choices = Item.objects.all()
def choice_label(self, choice):
"""
Return the human-readable representation of a choice.
"""
barcode = Item.objects.get(pk=self.choice_value(choice)).barcode
return force_text(barcode)
autocomplete_light.register(ItemAutocomplete)
For more help you can have a look at the source code.

Related

Should objects know of the objects they're used in?

class Item:
def __init__(self, box, description):
self._box = box
self._description = description
class Box:
def __init__(self):
self.item_1 = Item(self, 'A picture')
self.item_2 = Item(self, 'A pencil')
#etc
old_stuff = Box()
print(old_stuff.item_1.box.item_1.box.item_2.box.item_1)
Above is shown an example piece of code which demonstrates my problem better than I ever could with plain text. Is there a better way to find in what box something is? (In what box is the picture?) Since I am not particularly fond of the above solution because it allows for this weird up and down calling which could go on forever. Is there a better way to solve this problem or is this just a case of: If it's stupid and it works, it ain't stupid.
Note: this trick isn't python specific. It's doable in all object-oriented programming laguages.
There is no right or wrong way to do this. The solution depends on how you want to use the object.
If your use-case requires that an item know in which box it is stored, then you need a reference to the box; if not, then you don't need the association.
Similarly, if you need to which items are in a given box, then you need references to the items in the box object.
The immediate requirement (that is, the current context) always dictates how one designs a class model; for example, one models an item or a box differently in a UI layer from how one would model it in a service layer.
You must introduce new class - ItemManager or simply dict or other external structure to store information about which box contain your item:
class Item:
def __init__(self, description):
self.description = description
class Box:
def __init__(self, item_1, item_2):
self.item_1 = item_1
self.item_2 = item_2
class ItemManager:
def __init__(self):
self.item_boxes = {}
def register_item(self, item, box):
self.item_boxes[item] = box
def deregister_item(self, item):
del self.item_boxes[item]
def get_box(self, item):
return self.item_boxes.get(item, None)
item_manager = ItemManager()
item_1 = Item("A picture")
item_2 = Item("A pencil")
item_3 = Item("A teapot")
old_stuff = Box(item_1, item_2)
item_manager.register_item(item_1, old_stuff)
item_manager.register_item(item_2, old_stuff)
new_stuff = Box(item_3, None)
item_manager.register_item(item_3, new_stuff)
box_with_picture = item_manager.get_box(item_2)
print box_with_picture.item_1.description
Also see SRP: an item should not know which box contains it.

POST a list to the API, update or create depending on the existence of that instance

I have a view which allows me to post multiple entries to a model. Currently if I add all new entries, they are added successfully. But if I add any entry for which the pk already exists, it naturally throws a serializer error and nothing gets updated.
I wish to write a method which will let me post multiple entries, but automatically either update an existing one OR add a new one successfully depending the existence of that instance.
The idea of a customized ListSerialzer is the closest thing I came across to achieve this but still not clear if I can do this.
Has anyone ever implemented anything like this ?
In views.py:
def post(self,request,format=None):
data = JSONParser().parse(request)
serializer = PanelSerializer(data=data,many=True)
if serializer.is_valid():
serializer.save()
return JsonResponse({"success":"true","content":serializer.data}, status=201)
return JsonResponse({'success': "false",'errorCode':"1",'errorMessage':serializer.errors}, status=400)
in serializers.py:
class PanelSerializer(serializers.ModelSerializer):
class Meta:
model = Panel
fields = ('pId','pGuid','pName', 'pVoltage', 'pAmperage','pPermission', 'pPresent', 'pSelf','pInfo')
def create(self, validated_data):
logger.info('Information incoming_1!')
print ("Atom")
return Panel.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.pId = validated_data.get('pId', instance.pId)
instance.pGuid = validated_data.get('pId', instance.pGuid)
instance.pName = validated_data.get('pName', instance.pName)
instance.pVoltage = validated_data.get('pVoltage', instance.pVoltage)
instance.pAmperage = validated_data.get('pAmperage', instance.pAmperage)
instance.pPermission = validated_data.get('pPermission', instance.pPermission)
instance.pPresent = validated_data.get('pPresent', instance.pPresent)
instance.pSelf = validated_data.get('pSelf', instance.pSelf)
instance.pInfo = validated_data.get('pInfo', instance.pInfo)
instance.save()
return instance
This is how the code stands as of now. I believe I will mainly need to either work on the update method of my serializer or first change it to a ListSerializer and write some custom logic again in the update method.

Integrating custom module with odoo website

I have a custom module called admission form with some fields suppose name, phone, email, etc. how to add this form to website module using templatr to work like contact form in contact us page when filled data is automatically created in new leads. instead of leads i want it to transfer the information to my custom module.
Summary: instruction to relate website to custom module.
class AdmissionForm(models.Model):
_name = 'admission.form'
name = fields.Char()
phone = fields.Integer()
email = fields.Char()
faculty = field.Many2one('res.faculty')
In ODOO Whenever you want to performe some task at the time of creation ,then you must override create method in your model (:admission.form).
Let say you want to create a partner just after creation of the record in admission.form model then follow these steps:
Override create method .
Call the super with the argument and hold it value in result.
Now do your task .
return result.
Code snippet:
#api.model
def create(self, vals):
result = super(AdmissionForm, self).create(vals)
new_vals = dict(name=result.name,
phone=result.phone,
email=result.email,
is_company=1,
supplier=1,
customer=1,
)
self.env['res.partner'].create(new_vals)
return result
In case if you want to do some task before creation of record then follow these steps:
Override create method .
Do your task .
Call the super with the argument and return it.
#api.model
def create(self, vals):
new_vals = dict(name=vals.get('name'),
phone=vals.get('phone'),
email=vals.get('email'),
is_company=1,
supplier=1,
customer=1,
)
partner=self.env['res.partner'].create(new_vals)
return super(AdmissionForm, self).create(vals)

Yii 1.x how to change model name in POST (CActiveForm)

Its posible change model name in post/get?
I have model with large names, like "VerLargeModelName" and many parameters.
It does not fit in GET (query string limit).
Update:
i need just change generated inputs from CActiveForm (change LongModelName[a] to short[a])
You can just change the name. You can do this like this echo $form->textFieldBlock($model,'name',array('name' => 'x["name"]') or whatever you want. You could also create a class (widget) with does this for your.
class MyActiveForm extends CActiveForm {
public function hiddenField($model, $attribute, $htmlOptions = array()) {
if(isset($htmlOptions['shortName'])) {
$htmlOptions['name'] = $htmlOptions['shortName'] . "[".$attribute."]";
unset($htmlOptions['shortName']);
}
return parent::hiddenField($model, $attribute, $htmlOptions);
}
}
You change CActiveFrom from the widget to MyActiveForm. Then use $form->textFieldBlock($model,'name',array('shortName' => 'x'). You could also change the above code to always change to a shortname without the htmlOptions. So that it is always x. However you could not have two form at once in this case. Benifit is that you would not need to add array('shortName' => 'x') to all of them, but just change CActiveFrom to MyActiveForm. So that would save you time, but cost your flexibility (with you might need later on maybe).
You have to create a function offcourse for every input field you want to use from ActiveRecord. The name of the element would become x['name']
In the controller you could simply do $model->attributes = $_POST['x'].

Django Rest Framework custom permissions per view

I want to create permissions in Django Rest Framework, based on view + method + user permissions.
Is there a way to achieve this without manually writing each permission, and checking the permissions of the group that the user is in?
Also, another problem I am facing is that permission objects are tied up to a certain model. Since I have views that affect different models, or I want to grant different permissions on the method PUT, depending on what view I accessed (because it affects different fields), I want my permissions to be tied to a certain view, and not to a certain model.
Does anyone know how this can be done?
I am looking for a solution in the sort of:
Create a Permissions object with the following parameters: View_affected, list_of_allowed_methods(GET,POST,etc.)
Create a Group object that has that permission associated
Add a user to the group
Have my default permission class take care of everything.
From what I have now, the step that is giving me problems is step 1. Because I see no way of tying a Permission with a View, and because Permissions ask for a model, and I do not want a model.
Well, the first step could be done easy with DRF. See http://www.django-rest-framework.org/api-guide/permissions#custom-permissions.
You must do something like that:
from functools import partial
from rest_framework import permissions
class MyPermission(permissions.BasePermission):
def __init__(self, allowed_methods):
super().__init__()
self.allowed_methods = allowed_methods
def has_permission(self, request, view):
return request.method in self.allowed_methods
class ExampleView(APIView):
permission_classes = (partial(MyPermission, ['GET', 'HEAD']),)
Custom permission can be created in this way, more info in official documentation( https://www.django-rest-framework.org/api-guide/permissions/):
from rest_framework.permissions import BasePermission
# Custom permission for users with "is_active" = True.
class IsActive(BasePermission):
"""
Allows access only to "is_active" users.
"""
def has_permission(self, request, view):
return request.user and request.user.is_active
# Usage
from rest_framework.views import APIView
from rest_framework.response import Response
from .permissions import IsActive # Path to our custom permission
class ExampleView(APIView):
permission_classes = (IsActive,)
def get(self, request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)
I took this idea and got it to work like so:
class genericPermissionCheck(permissions.BasePermission):
def __init__(self, action, entity):
self.action = action
self.entity = entity
def has_permission(self, request, view):
print self.action
print self.entity
if request.user and request.user.role.access_rights.filter(action=self.action,entity=self.entity):
print 'permission granted'
return True
else:
return False
I used partially in the decorator for the categories action in my viewset class like so:
#list_route(methods=['get'],permission_classes=[partial(genericPermissionCheck,'Fetch','Categories')])
def Categories(self, request):
"access_rights" maps to an array of objects with a pair of actions and object e.g. 'Edit' and 'Blog'