StringField is defined as unique, but duplicates are saved silently - django

I defined a simple Document, like this:
class Company(Document):
screen_name = StringField(max_length=100, required=True, unique=True)
official_name = StringField(required=False)
meta = {
'indexes': [{'fields': 'screen_name', 'unique': True}]
}
but when I am writing a test
#use_tdb
def test_company3():
""" test company2 """
company = Company(screen_name='asdasd')
company.save()
company = Company(screen_name='asdasd')
with nt.assert_raises(OperationError):
company.save()
pprint([(x.id, x.screen_name,) for x in Company.objects.all()])
It actually saves both of them. And I see in output:
[(ObjectId('4f719f915c121a21ad000003'), u'asdasd'),
(ObjectId('4f719f915c121a21ad000004'), u'asdasd')]
Any ideas, what I've done wrong?
Thanks

That is may be required drop_collection.
def test_company3():
""" test company2 """
Company.drop_collection()
company = Company(screen_name='asdasd')
company.save()
company = Company(screen_name='asdasd')
with nt.assert_raises(OperationError):
company.save()
pprint([(x.id, x.screen_name,) for x in Company.objects.all()])
See this tests. Mongoengine is all tests is passed.
https://github.com/hmarr/mongoengine/blob/master/tests/document.py#L875
Mongoengine team Recently relaeed 0.6.3.

Related

django rest datatables, filter experts by meeting objectives

I need to filter all Experts by past objectives.
I have a minimal runnable example at https://github.com/morenoh149/django-rest-datatables-relations-example (btw there are fixtures you can load with test data).
my models are
class Expert(models.Model):
name = models.CharField(blank=True, max_length=300)
class Meeting(models.Model):
user = models.ForeignKey(User, on_delete=models.SET_NULL, blank=True, null=True)
expert = models.ForeignKey(Expert, on_delete=models.SET_NULL, blank=True, null=True)
objective = models.TextField(null=True, blank=True)
my datatables javascript
$("#table-analyst-search").DataTable({
serverSide: true,
ajax: "/api/experts/?format=datatables",
ordering: false,
pagingType: "full_numbers",
responsive: true,
columns: [
{
data: "objectives",
name: "objectives",
visible: false,
searchable: true,
render: (objectives, type, row, meta) => {
return objectives;
}
},
],
});
My serializer
class ExpertSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(read_only=True)
objectives = serializers.SerializerMethodField()
class Meta:
model = Expert
fields = (
"id",
"objectives",
)
def get_objectives(self, obj):
request = self.context["request"]
request = self.context["request"]
meetings = Meeting.objects.filter(
analyst_id=request.user.id, expert_id=obj.id
).distinct('objective')
if len(meetings) > 0:
objectives = meetings.values_list("objective", flat=True)
objectives = [x for x in objectives if x]
else:
objectives = []
return objectives
When I begin to type in the datatables.js searchbar I get an error like
FieldError at /api/experts/
Cannot resolve keyword 'objectives' into field. Choices are: bio, company, company_id, created_at, description, email, favoriteexpert, first_name, id, is_blocked, last_name, meeting, middle_name, network, network_id, position, updated_at
Request Method: GET
Request URL: http://localhost:8000/api/experts/?format=datatables&draw=3&columns%5B0%5D%5Bdata%5D=tags&columns%5B0%5D%5Bname%5D=favoriteexpert.tags.name&columns%5B0%5D%5Bsearchable%5D=true&columns%5B0%5D%5Borderable%5D=false&columns%5B0%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B0%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B1%5D%5Bdata%5D=desc&columns%5B1%5D%5Bname%5D=&columns%5B1%5D%5Bsearchable%5D=false&columns%5B1%5D%5Borderable%5D=false&columns%5B1%5D%5Bsearch%5D%5Bvalue%5D=&columns%
fwiw, in pure django orm what I want to accomplish would be something like
Expert.objects.filter(
pk__in=Meeting.objects.filter(
objective__icontains='Plastics', user=request.user
).values('expert')
)
How can I filter experts by historical meeting objectives?
The reason for the error is that django-rest-framework-datatables is trying to translate the request into a query which can be run against the Expert table.
In your JS, you're asking for a field called 'objectives' to be returned, but there is no such field on the Expert model.
You could probably achieve what you are trying to do using the django-filter integration. In this case, you could set up a filter on the FK reference to the Meeting table. The example app demonstrates how to do this.
I think the best way to understand what's going on is to get the example application running, and if possible, set breakpoints and step through.
Incidentally, if you want to get the search box to work correctly, then you need to define a global_q() method. This is also covered in the example app.
I ended up authoring a custom django-filter
class AssociatedMeetingCharFilter(filters.CharFilter):
def global_q(self):
"""
Uses the global filter to search a meeting field of meetings owned by the logged in user
"""
if not self._global_search_value:
return Q()
kw = "meeting__{}__{}".format(self.field_name, self.lookup_expr)
return Q(**{
kw: self._global_search_value,
"meeting__user_id": self.parent.request.user.id or -1,
})
class ExpertGlobalFilterSet(DatatablesFilterSet):
name = GlobalCharFilter(lookup_expr='icontains')
objectives = AssociatedMeetingCharFilter(field_name='objective', lookup_expr='icontains')
full example at https://github.com/morenoh149/django-rest-datatables-relations-example

How to use one model as source for 'choices' in another model?

I have 3 models: User, UserProfile and Programme. User holds the names of all users;
class User(AbstractUser):
first_name = model.Charfield(...)
last_name = model.Charfield(...)
...
UserProfile contains the attributes associated with each user (e.g. sales manager(sm), program manager(pm), delivery manager(dm) etc.
class UserProfile(model.Model):
user = model.ForeignKey(User, on_delete...)
sm = model.BooleanField(default = False, editable=True...)
pm = model.BooleanField(default = False, editable=True...)
dm = model.BooleanField(default = False, editable=True...)
A User may have any combination of UserProfile attributes. For example:
User-1: sm
User-2: sm, pm
User-3: dm
User-4: sm, dm
...
Every programme in Programme must have a user assigned for each of sm, pm, dm so my challenge is finding a way to generate a 'choices' list for each of sm, pm and dm limited to Users with the appropriate attribute.
class Programme(model.Models):
programme_name = models.Charfield(...)
AND ESSENTIALLY:
sm = only users with userprofile.sm = True
pm = only users with userprofile.pm = True
dm = only users with userprofile.dm = True
I've tried adding a function to UserProfile then referencing it in Programme:
UserProfile(model.Models):
....
def get_pm(self):
pm_list = []
pm = UserProfile.objects.filter(pm=True)
for i in pm:
pm_list.append(i.user.last_name)
return pm_list
and in Programme:
Programme(model.Models):
pm = models.Charfield(choices=UserProfile.get_pm, ...
but this generates the error: 'choices' must be an iterable (e.g., a list or tuple).
Similarly, I've tried adding the same function to Programmes/models.py but this generates the same error.
I know I'm missing the obvious but all help appreciated.
You dont need to create a separate model for User profile:
class User(AbstractUser):
first_name = model.Charfield(...)
last_name = model.Charfield(...)
POST_CHOICES = (
('sm', ("sm")),
('sm', ("pm")),
('sm', ("dm")),
)
post=models.CharField(choices=POST_CHOICES,max_length=150, blank=True)
programme_name = models.Charfield(max_length=150, blank=True)
You can filter out the users who are sm,for example using filter queries or you can use model managers for this
Well, after a ridiculous amount of reading, trial and error, a simple solution emerges: Simple override the form fields using an appropriate query -
class ProgrammeCreateForm(forms.ModelForm):
class Meta:
model = Programme
fields = [
'name', 'company', 'status', 'pm', 'sm', 'dm', 'idm','start_date', 'end_date', 'delivery_type'
]
def __init__(self, *args, **kwargs):
super(ProgrammeCreateForm, self).__init__(*args, **kwargs)
sm_choices = UserProfile.objects.filter(sm=True)
pm_choices = UserProfile.objects.filter(pm=True)
dm_choices = UserProfile.objects.filter(dm=True)
idm_choices = UserProfile.objects.filter(idm=True)
self.fields['sm'] = forms.ModelChoiceField(queryset=sm_choices)
self.fields['pm'] = forms.ModelChoiceField(queryset=pm_choices)
self.fields['dm'] = forms.ModelChoiceField(queryset=dm_choices)
self.fields['idm'] = forms.ModelChoiceField(queryset=idm_choices)

Why my relation didn't work in my object with sale_order object

I used odoo 10, my relation with my new object to sale.order didn't work, I used #api.onchange('product_id') only to check how my relation work...
here's my 'paket.perjalanan' object design
from odoo import models, fields, api
class Paket(models.Model):
_name = 'paket.perjalanan'
name = fields.Char(string='Reference', readonly=True)
product_id = fields.Many2one('product.product', string='Sale', domain=[('type','=','service')], required=True)
.......
travel_line = fields.One2many('sale.order', 'travel_id', string='Paket Perjalanan')
#api.onchange('product_id')
def testing(self):
print self.travel_line
here's my 'sale.order' inherit object
from odoo import models, fields, api
class SaleOrderCustom(models.Model):
_inherit = 'sale.order'
invoice_address = fields.Many2one('res.partner', string='Invoice Address', required=True)
delivery_address = fields.Many2one('res.partner', string='Delivery Address', required=True)
travel_id = fields.Many2one('paket.perjalanan', string='Travel Package', domain=[('state', '=', 'confirmed')])
document_line = fields.One2many('sale.document.line', 'document_id', string='Dokumen Line', required=True)
passport_line = fields.One2many('sale.passport.line', 'passport_id', string='Passport Line')
When I run #api.onchange('product_id') it only shows sale.order() it should shows like this sale.order('some_id') can anyone give me advice ?
Add #api.depends
#api.onchange('product_id')
#api.depends('travel_line')
def testing(self):
print self.travel_line
Hope it will help you.

Create a dynamic search form in Django

in my Django 1.5 model I'm trying to create a form that let me book a place in a study room.
The study room is defined as follows in models.py:
class StudyRoom(models.Model):
name = models.CharField(max_length = 30, primary_key = True)
city = models.CharField(max_length = 30)
placesno = models.IntegerField()
def __unicode__(self):
return self.name
and this is the relative form:
class SearchSeat(forms.Form):
morning = 'AM'
evening = 'PM'
daysection_choices = ((morning, 'Morning'), (evening, 'Evening'),)
city = forms.ChoiceField(choices = [], required=True, label='Select a city?')
study_room = forms.ChoiceField(choices = [], required=True, label='Select a study room?')
day = forms.DateField(label = 'Select a day', required=True, widget=forms.extras.SelectDateWidget(years=range(2014, 2015)))
section = forms.ChoiceField(choices=daysection_choices, label = 'Morning (form 8.00 to 13.00) or evening (from 13.00 to 18..)?')
def __init__(self, *args, **kwargs):
super(SearchSeat, self).__init__(*args, **kwargs)
self.fields['city'].choices = StudyRoom.objects.all().values_list("city","city").distinct()
search_city = self.fields['city']
self.fields['study_room'].choices = StudyRoom.objects.filter(city = search_city).values_list("name")
The objective was to let the user select the city and then filter the study room and show only the ones in the selected city, all in one form without changing page.
The code written like this doesn't work and I'm starting to think that there isn't a solution without using client side side scripting (it's a Django+Python project so we are supposed to use only those two instruments).
For your problem there can only be a solution with client scripting:
At the moment the html is created, the study-room choices are not determined. This means that on city change, you will need to manipulate your html, which means client side programming like:
$(document).ready(function(){
$('#id_city').on('change', function(){
...
})
);
There is no need for an ajax request, though: you could save the choices into a 'data' attribute in your html and access it using: http://api.jquery.com/data/
You would need then to modify your fields:
self.fields['city'] = forms.Select(attrs={'data-london':'[json_dump of londondata], 'data-paris': '[json_dump of paris study rooms]' etc})
Depending on the amount of data, the ajax call would be a cleaner solution

Django Comparing user's list

I have a like feature which allows students to like in other pictures.
def LikePicture(request,picture_id):
p = Picture.objects.get(pk=picture_id)
new_like, created = Like.objects.get_or_create(user=request.user, picture_id=picture_id)
return HttpResponseRedirect(reverse('world:Boat', kwargs={'animal_id': the_id }))
At the moment , I'm trying to implement a restriction toward the people who likes a particular picture.
I want only the people who are friends with a particular users to like their's picture and the only way
I can do this is by implementing a friend models.
2 Users can only be friends if both users add each other.
I'm planning to use this friendship models unless someone has a better friendship models that we can both use to implement the restriction.
class Friendship(models.Model):
from_friend = models.ForeignKey(User, related_name='friend_set')
to_friend = models.ForeignKey(User, related_name='to_friend_set')
def __unicode__(self):
return u'%s, %s' % (
self.from_friend.username,self.to_friend.username)
class Meta:
unique_together = (('to_friend', 'from_friend'), )
We can bulid a relationship with
>>> user1 = User.objects.get(id=1)
>>> user2 = User.objects.get(id=2)
>>> friendship1 = Friendship(from_friend=user1, to_friend=user2)
>>> friendship1.save()
>>> user1.friend_set.all()
[<Friendship: user1, user2>, <Friendship: user1, user3>]
but inorder to become friends . the other users has to add the other users.
>>> friendship3 = Friendship(from_friend=user2, to_friend=user1)
>>> friendship3.save()
>>> user2.friend_set.all()
[<Friendship: user2, user1>]
Now , The problem is how can we edit the like function so it would only allows friends to like a picture.
I have thought of a way but I couldn't find a way to implement it into my like function. My idea is because we can grab the User object who own the picture and the guy who's trying to like the picture . We can compare each other friendlist .
We get the user object who own the picture and we get the user object whose trying to like the picture.We then compare if the user who's own the picture has the user who's trying to like his picture on his friendlist >>> user1.friend_set.all()
and we do it in reverse . If the user owner's picture is inside the request.user friendlist .Allow Like!!! .
So it's like , if both users have each other in the same friendlist . Allow like!!!
It would be something similar to this function
def Like(request,picture_id):
user1 = User.objects.get(user=request.user) # The Guy who trying to like the picture
p = Picture.objects.get(pk=picture_id)
user2 = User.objects.get(picture=p) # The owner of the picture
if user1 is in user2.friend_set.all() AND if user2 is in user1.friend_set.all():
new_like, created = Like.objects.get_or_create(user=request.user, picture_id=picture_id)
else:
message ('You can only like if you are an friend ')
return HttpResponseRedirect(reverse('world:Boat', kwargs={'animal_id': the_id }))
return HttpResponseRedirect(reverse('world:Boat', kwargs={'animal_id': the_id }))
Or we can compare Users object
>>> [friendship.to_friend for friendship in
user1.friend_set.all()]
[<User: user2>, <User: user3>]
Little bit improvement required:
class FriendshipManager(models.Manager):
def is_friends(self, user_a, user_b):
if self.get_query_set().filter(
user__id=user_a.id, friend__id=user_b.id, is_accepted=True).exists() or \
self.get_query_set().filter(
user__id=user_b.id, friend__id=user_a.id, is_accepted=True).exists():
return True
else:
return False
class Friendship(models.Model):
user = models.ForeignKey(User)
friend = models.ForeignKey(User, related_name='friends')
is_accepted = models.BooleanField(default=False)
objects = FriendshipManager()
def __unicode__(self):
return u'%s, %s' % (
self.user.username, self.friend.username)
class Meta:
unique_together = (('user', 'friend'), )
def Like(request, picture_id):
user = request.user
p = get_object_or_404(Picture, pk=picture_id)
pic_owner = p.user # i hope you have user relationship with pic here
if Friendship.objects.is_friends(user, pic_owner) \
pic_owner.id == user.id:
# if the pic owner and requested user are friends
# or user is liking his own pic
new_like, created = Like.objects.get_or_create(
user=user, picture=p)
else:
message ('You can only like if you are friends')
return HttpResponseRedirect(
reverse('world:Boat', kwargs={'animal_id': the_id }))
return HttpResponseRedirect(
reverse('world:Boat', kwargs={'animal_id': the_id }))
Added is_accepted field to make sure other person approved the friend request.
Added is_friendsmethod in manager which will be used to check if two users are friends.
In view also checked if requested user and picture owner are same then it means user can like its own posted picture. This code is untested but I hope this will serve you well.