Django models create data duplicate - python

1.Models's name is UserRecord.
2.Below is the code of my view.
#login_required
def data(request, page, keyword,strEncode):
current_username = request.user.username
data_s = dosomething() #It takes a long time!!!
UserRecord.objects.get_or_create(user=User.objects.get(username=current_username),MyRecords=keyword) # in order to create unique value
# or use below method
# if not UserRecord.objects.filter(user=User.objects.get(username=current_username),MyRecords=keyword):
# UserRecord.objects.create(user=User.objects.get(username=current_username),MyRecords=keyword)
return JsonResponse(data_s, safe=False)
Requested below URL several times with no interval,something like concurrent threading .
http://127.0.0.1:8000/data/1/test/english/
After this operation done,MyRecords column is populated by duplicate values.
I found something in Django document to use 'with transaction.atomic' to deal with this problem but it did not work.

You don't need to get user by User.objects.get(user=User.objects.get(username=current_username))
Instead use request.user for same.
#login_required
def data(request, page, keyword,strEncode):
current_user = request.user
data_s = dosomething()
UserRecord.objects.get_or_create(user=current_user,MyRecords=keyword) # in order to create unique value
return JsonResponse(data_s, safe=False)
And MyRecords=keyword will create a new record every time a new keyword is passed in the def data view, so please review your code.

Mysql
class UserRecord(models.Model):
user = models.ForeignKey(User)
MyRecords = models.CharField(max_length=128)
class Meta:
unique_together = (("user", "MyRecords"),) #mutil column uique idex
def __unicode__(self):
return self.user.username

Related

Django Rest Framework ListSerializer Partial Update

I'm writing a serializer to provide multiple partial updates to a django model. I'm following the example implementation that appears in the DRF api guide, reproduced below and linked here: https://www.django-rest-framework.org/api-guide/serializers/#customizing-multiple-update.
The following was retrieved from django-rest-framework documentation:
serializer.py
class BookListSerializer(serializers.ListSerializer):
def update(self, instance, validated_data):
# Maps for id->instance and id->data item.
book_mapping = {book.id: book for book in instance}
data_mapping = {item['id']: item for item in validated_data}
# Perform creations and updates.
ret = []
for book_id, data in data_mapping.items():
book = book_mapping.get(book_id, None)
if book is None:
ret.append(self.child.create(data))
else:
ret.append(self.child.update(book, data))
# Perform deletions.
for book_id, book in book_mapping.items():
if book_id not in data_mapping:
book.delete()
return ret
class BookSerializer(serializers.Serializer):
# We need to identify elements in the list using their primary key,
# so use a writable field here, rather than the default which would be read-only.
id = serializers.IntegerField()
...
class Meta:
list_serializer_class = BookListSerializer
In my code I'm getting a NotImplementedError('update() must be implemented.') in my views.py when .save() is called on the serializer that is returned.
My understanding is that the ListsSerializer overrides the .update(), so could anyone help explain why I'm getting the NotImpletmentedError?
views.py
elif request.method == 'PATCH':
data = JSONParser().parse(request)
books = Book.objects.all()
# both partial and many set to True
serializer = BookSerializer(books, data=data, partial=True, many=True)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data)
return JsonResponse(serializer.errors, status=400)
With the help of #luistm, I managed to solve this. Continuing with the DRF example above my implementation of the update() override in the bookSerializer class was as below.
serializer.py
class BookSerializer(serializers.Serializer):
# We need to identify elements in the list using their primary key,
# so use a writable field here, rather than the default which would be read-only.
id = serializers.IntegerField()
...
class Meta:
list_serializer_class = BookListSerializer
def update(self, instance, validated_data):
"""update the page number of the book and save"""
instance.page = validated_data.get('page', instance.page)
instance.save()
return instance

Return user if exists or create new

I'm trying to implement a view in Django/DRF that given a body containing facebook_id, first_name, last_name and email, the function checks if a user already exists in the database with either the email or the facebook_id. If not, then I create a new user and save it.
I'm trying to do this with a serialzier and I'm not sure what the correct approach is. I want to use the same serializer I used for sign ups which is this:
class ClientSerializer(serializers.ModelSerializer):
class Meta:
model = Client
exclude = ['password']
It contains a lot of unnecessary fields that I wont need in this new view (such as phone number). Should I create a new seralizer just for this view? Also should I depend on the is_valid() function on the serializer to tell me if the user exists (if it raises an error) or is that too unreliable since the fields might be invalid?
Here's what I have so far:
#api_view(['POST'])
def facebook_login(request):
print(request.data)
serializer = ClientSerializer(data=request.data)
if serializer.is_valid():
# create a new user
else:
# possibly perform a get on the database to return the existing user?
return Response(serializer.errors)
You could do something like this.
#api_view(['POST'])
def facebook_login(request):
print(request.data)
serializer = ClientSerializer(data=request.data)
serializer.Meta.read_only_fields = ['x', 'y']
if serializer.is_valid():
# create a new user
else:
# possibly perform a get on the database to return the existing user?
return Response(serializer.errors)
The read only fields will be a list of fields that you don't want the user to use on creation, but you still want to be in the view on retrival.
You can use this,
#api_view(['POST'])
def facebook_login(request):
print(request.data)
data = request.data
serializer = ClientSerializer(data=data)
email = data.get("email")
obj = Client.objects.filter(email=email)
if obj.exists():
return obj
elif serializer.is_valid():
f_name = data.get("first_name")
l_name = data.get("last_name")
email = data.get("email")
# more that you need
Client.objects.create(first_name=f_name, last_name=l_name, email=email, .....)
return # whatever you want
else:
# whatever you want
I would do it in the following way
api_view(['POST'])
def facebook_login(request):
client = None
email, fbid = request.data.get('email',None), request.data.get('facebook_id', None)
# Assuming that email or facebook id is provided, not both
if email is not None and Client.objects.filter(email=email).exists():
client = Client.objects.filter(email=email).get()
elif fbid is not None and Client.objects.filter(facebook_id=fbid).exists():
client = Client.objects.filter(facebook_id=fbid).get()
else:
serializer = ClientSerializer(data=request.data)
if serializer.is_valid():
client = serializer.save()
else:
return Response(serializer.errors)
return Response(ClientSerializer(instance=client).data)
It can be probably simplified in some way, but this would be my approach.

Django session passes argument from a view to another but sets the same value for all user instances

I am passing an (is_followed) parameter from one class based view FollowToggleAPIView to another UserDetailAPIVIew. I do this using Django session (from reading other thread on this platform) in the hope of displaying the follow-status (True or False) of the user_to_toggle variable on the UserSingleProfileSerializer.
Here are my views:
class UserDetailAPIVIew(generics.RetrieveAPIView):
'''
Displays a list of a user's posts
'''
serializer_class = UserSingleProfileSerializer
queryset = User.objects.all()
def get_object(self):
self.object = get_object_or_404(User,
username__iexact=self.kwargs.get('username')
)
return self.object
def get_serializer_context(self):
'''
passing the extra is_following argument to the UserDetailAPIVIew
'''
context = super(UserDetailAPIVIew, self).get_serializer_context()
is_followed = self.request.session.get('followed')
context.update({'followed': is_followed})
return context
class FollowToggleAPIView(APIView):
'''
Uses the custom model manager for user toggle follow
'''
def get(self, request, username, format=None):
user_to_toggle = get_object_or_404(User, username__iexact=username)
me = request.user
message = 'Not allowed'
if request.user.is_authenticated():
is_followed = UserProfile.objects.toggle_follow(me, user_to_toggle)
request.session['followed'] = is_followed
return Response({'followed': is_followed})
return Response({'message': message}, status=400)
The toggle_follow method is defined in the custom model manager as follows:
class UserProfileManager(models.Manager):
def toggle_follow(self, user, to_toggle_user):
''' follow unfollow users '''
user_profile, created = UserProfile.objects.get_or_create(user=user)
if to_toggle_user in user_profile.following.all():
user_profile.following.remove(to_toggle_user)
added = False
else:
user_profile.following.add(to_toggle_user)
added = True
return added
class UserProfile(models.Model):
'''
Extends the Django User model
'''
user = models.OneToOneField(settings.AUTH_USER_MODEL,
related_name='profile')
following = models.ManyToManyField(settings.AUTH_USER_MODEL,
blank=True,
related_name='followed_by')
objects = UserProfileManager()
def get_absolute_url(self):
return reverse_lazy('profiles:detail',
kwargs={'username':self.user.username})
def __str__(self):
return 'Username: {} [ Followers ({});
Following({})]'.format(self.user.username,
self.user.followed_by.all().count(),
self.following.all().count())
The urls.py:
urlpatterns = [
url(r'^(?P<username>[\w.#+-]+)/$', UserDetailAPIVIew.as_view(),
name='user-posts-api'),
url(r'^(?P<username>[\w.#+-]+)/follow/$',
FollowToggleAPIView.as_view(), name='follow-api'),
]
The only problem is that the value of (is_followed) displayed in UserSingleProfileSerializer is set for all user instances at once (not for the specific user we want to follow).
I am certainly not following/unfollowing all users at the same time (since the FollowToggleAPIView targets a specific user by his username).
I want to know how can I transfer the value of (is_followed) only to the specific user (user_to_toggle) in the UserDetailAPIVIew. Thank you in advance.
The session is completely the wrong thing to use here. You're storing a single "followed" value which only records the last user they toggled and has no relation to the profile they're actually viewing.
Instead of doing this, you should simply query in the UserDetailAPIVIew the followed status of the specific user.
def get_serializer_context(self):
context = super(UserDetailAPIVIew, self).get_serializer_context()
is_followed = self.request.user.profile.following.filter(username=self.object).exists()
context.update({'followed': is_followed})
return context
Note also, your toggle method is itself very inefficient - there's no need to retrieve every follow from the database just to check whether the current user is among them. Use exists again:
user_profile, created = UserProfile.objects.get_or_create(user=user)
if user_profile.following.filter(username=to_toggle_user).exists():

django 1.8 - 'NoneType' object has no attribute 'aggregate'

The error is self clear. But I was puzzled at how to solve it.
If the form entry get the corresponding record in the database, then there is no error. But if I enter something in the form that doesn't have corresponding data in the database, then it would appear the error of 'NoneType' object has no attribute 'aggregate'. I know the reason is because no query result, so in def context it cannot continue the calculation.
So if there is anyway if not finding corresponding record in the database, then it will not continue to do the calculation in "def get_context_data" to avoid this error? So the page will just remain on the current data entry page without redirecting to the another page to show the result.
Any suggestion is appreciated, thanks in advance.
views.py
from django.contrib import messages
class FinalView(ListView):
context_object_name = 'XXX'
template_name = 'XXX.html'
model = Final
def get_queryset(self):
form = InputForm(self.request.GET)
if form.is_valid():
department = form.cleaned_data['department']
person = form.cleaned_data['person']
if department !="" and person !="":
if Final.objects.filter(department=department,person=person).exists():
queryset=Final.objects.filter(department=department,person=person)
return queryset
else:
form.add_error(ValidationError('No corresponding data exists'))
elif department =="" and person !="":
if Final.objects.filter(person=person).exists():
queryset=Final.objects.filter(person=person)
return queryset
else:
form.add_error(ValidationError('No corresponding data exists'))
elif ........
else: #if form not valid
messages.error(request, "Error")
def get_context_data(self,**kwargs):
context["sales"] = self.get_queryset().aggregate(Sum('sales'))
EDIT as suggest
.........Before are the same....
def get_context_data(self,**kwargs):
query_set = self.get_queryset()
if query_set is not None:
context = super(FinalView, self).get_context_data(**kwargs)
context["sales"] = query_set.aggregate(Sum('sales'))
return context
Use the fact that django query sets are are lazy to your advantage, it won't make a database query till it needs the data so just split it up to do some validation
query_set = self.get_queryset()
context = super(FinalView, self).get_context_data(**kwargs)
if query_set is not None:
context['sales'] = query_set.aggregate(Sum('sales'))
return context
You may also want to make sure that all paths from get_queryset do actually return something to make this kind of validation easier.

Django: how to loop through boolean fields and set all to false

So, I have a table called "order" that has a foreign key with the table "store". The order table has a boolean field set by default to false. When a new order is created, I need to loop through the boolean values associated with each individual store and set the other orders to false and the new order to true. Not sure how to create the for loop for that. First I tried to set it into the view, but maybe it can be put into the forms.py file? This my create code so far.
def create(request):
if request.POST:
form = OrderForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/liquors/all')
else:
form = OrderForm()
args = {}
args.update(csrf(request))
args['form'] = form
return render_to_response('create_order.html', args)
Models provided upon request, you shouldn't need anything except the order model:
class Order(models.Model):
OrderID = models.AutoField(primary_key=True)
storeID = models.ForeignKey(Store)
DateCreated = models.DateField('Date Created', auto_now_add=True)
OrderName = models.CharField('Order Name', max_length=25 )
Active = models.BooleanField()
you must return render_to_response('create_order.html', args) one indentation back. so that validation form will not affected. you don't need to use csrf request if you are using render. I think there is no need to use OrderId in Order model, since it is automattically created. ie id
from django.shortcuts import render
from <appname>.models import Order,Store
def create(request):
if request.POST:
form = OrderForm(request.POST)
if form.is_valid():
#i just assume the storeid variable is exist in request.POST and it is ID.
store_data=Store.objects.get(id=request.POST['storeid'])
#here you might need to update the other orderform to false
Order.objects.filter(storeID=store_data).update(Active=False)
fo=Order(storeID=store_data,Active=True)
frm_order=OrderForm(request.POST,instance=fo)
frm_order.save()
return HttpResponseRedirect('/liquors/all')
else:
form = OrderForm()
return render(request,'create_order.html', {'form':form})
You can use the order object's meta object to loop through the fields. Ex.
for field in order._meta.fields():
if type(field) = django.db.models.fields.BooleanField:
setattr(order, field.name, True)

Categories