Im importing an xls file with django import-export and all working fine, now i need delete the rows that has the same strings, i mean
id - name
1 - Jhon
2 - Jhon
3 - Peter
Only insert in DB when importing the rows 2 and 3
Until now, i have this:
class ProyectosResource(resources.ModelResource):
#repeated_rows = fields.Field()
class Meta:
model = Proyectos
class ProyectosAdmin(ImportExportModelAdmin):
resource_class = ProyectosResource
I don't know if it's the right way to do this but I will do this in before_import function:
class ProyectosResource(resources.ModelResource):
#repeated_rows = fields.Field()
class Meta:
model = Proyectos
def before_import(self, dataset, dry_run):
"""
Make standard corrections to the dataset before displaying to user
"""
list = []
i = 0
last = dataset.height - 1
while i <= last:
#adding each name to a list
if ("the name is not in the list (take care about capitalizes letters)"):
dataset.rpush((dataset.get_col(0)[0], dataset.get_col(1)[0])) # add this line to the bottom
list = list.append(dataset.get_col(1)[0]) # add the name to the list
dataset.lpop() # erase it from the top (first line)
else :
#the name is already in the list
dataset.lpop() # simply erase it (first line) from the dataset
i = i + 1
Here is the doc of Tablib to manipulate Datasets !
You can do every test you want in before_import function, checking id for foreignKey relations...
Related
i have user model
class User(models.Model):
first_name = models.CharField(max_length=30)
and order model
class Order(models.Model):
user = models.ForgienKey(User)
product_name = models.CharField(max_length=30)
creating 2 user
hi = User.objects.create(firs_name = 'hi')
bye = User.objects.create(firs_name = 'bye')
i created 3 orders
Order.objects.create(product_name='nokia',user=hi)
Order.objects.create(product_name='samsung',user=hi)
Order.objects.create(product_name='nokia',user=bye)
so how to count nokia has 2 users and samsung has 1 user in django using filter or aggregate or annotate? and ouput something like this(should in orderby count value)
{
"nokia":"2",
"samsung":"1"
}
Django 1.8
try this you will get your output in json format
from django.db.models import Count
Order.objects.values('product_name')
.annotate(usercount=Count('user'))
objects.create(first_name = 'hi')
hi.save()
bye = User.objects.create(first_name = 'bye')
bye.save()
Here first_name should be same as field name in models.
l=[]
for o in Order.objects.all():
l.append(str(o.product_name))
l is list which contains all products(repeated) in a list
d = {x:l.count(x) for x in l}
print d
d gives data in dictionary format, which is
{'nokia': 2, 'samsung': 1}
you can you default count function to get the count of objects with or without the filter as per your need as following.
data_dict = {}
for cat in Order.objects.all()
data_dict.update({cat.product_name : 0 })
for obj in Order.objects.all():
if obj.product_name in data_dict.keys():
data_dict[obj.product_name] += 1
printing data_dict will give you your expected output
Use following query
orders = Order.objects
.values_list('product_name')
.annotate(usercount=Count('user'))
orders = dict(orders) # This must be of your json key values.
OR
orders = dict(orders.iterlists()) # This must be of your json key values.
So I have models like so:
class Leaderboard(models.Model):
pass
class Column(models.Model):
leaderboard = models.ForeignKey(Leaderboard, related_name="columns", on_delete=models.CASCADE)
related_columns = models.ManyToManyField(self)
index = models.PositiveIntegerField()
And serializers like so:
class ColumnSerializer(ModelSerializer):
related_columns = serializers.PrimaryKeyRelatedField(queryset=Column.objects.all(), many=True)
class Meta:
model = Column
fields = ('leaderboard', 'related_columns', 'index',)
class LeaderboardSerializer(ModelSerializer):
children = ColumnSerializer(many=True)
class Meta:
model = Leaderboard
fields = ('columns',)
So what I'd like to do is verify that any columns added to related_columns for ColumnSerializer already belong to its Leaderboard parent. I have tried many times to access the Leaderboard or a Leaderboard ID (like by manually specifying id in fields) during creation of the ColumnSerializer to verify, but LeaderboardSerializer` is not initialized before Column so I cannot verify the details.
Basically, I want to modify queryset=Column.objects.all() to be queryset=self.instance.leaderboard.columns.all()
However I don't have access to Leaderboard inside Column. For example, if I access self.parent.instance/initial inside ColumnSerializer it is None until inside Leaderboard.validate_columns(). One thing I've thought of is to just do the validation on the Leaderboard side, but I still think it should be "doable" to do this validation inside Column in case I ever want to edit those directly, without first going through a Leaderboard...
Here is how I solved this problem:
def validate_columns(self, columns):
if not columns:
raise serializers.ValidationError("Leaderboards require at least 1 column")
# Make sure all column indexes are unique
indexes = [column['index'] for column in columns]
if len(set(indexes)) != len(columns):
raise serializers.ValidationError("Columns must have unique indexes!")
# Make sure all column keys are unique
keys = [column["key"] for column in columns]
if len(set(keys)) != len(columns):
raise serializers.ValidationError("Columns must have unique keys!")
# Validate that column.computation_indexes points to valid columns
for column in columns:
if 'computation_indexes' in column and column['computation_indexes']:
for index in column['computation_indexes'].split(","):
try:
if int(index) not in indexes:
raise serializers.ValidationError(f"Column index {index} does not exist in available indexes {indexes}")
except ValueError:
raise serializers.ValidationError(f"Bad value for index, should be an integer but received: {index}.")
return columns
I make sure that the columns are unique (both in their keys and indexes) and that the columns they are referencing exist as well.
I have 3 different apps and each of them has unittest, if I run
python manage.py test categories coupons stores
I would get
IntegrityError(1452, 'Cannot add or update a child row: a foreign key constraint fails (`test_gocoupons`.`coupons_coupon`, CONSTRAINT `store_id_refs_id_bf6c0d9e` FOREIGN KEY (`store_id`) REFERENCES `stores_store` (`id`))'))
However if I run them individually they are fine.
This is a test mixin that all test cases uses:
# G is a function to create fixtures see django-dynamic-fixtures
class GoCouponsTestCaseMixin(object):
categories = []
stores = []
coupons = []
offers = []
def setUp(self):
self.categories.append(G(Category))
self.stores.append(G(Store, is_active=True))
# make sure we generate enough coupons for page 2
for i in range(1, settings.COUPON_PAGE_SIZE + 10):
coupon = G(Coupon, title='free', store=self.stores[0], is_active=True)
CouponCategory.objects.create(coupon=coupon, category=self.categories[0])
Offer.objects.create(start=timezone.now() + timedelta(days=-10), expire=timezone.now() + timedelta(days=10), coupon=coupon)
self.coupons.append(coupon)
Stacktrace show this line is causing the problem:
coupon = G(Coupon, title='free', store=self.stores[0], is_active=True)
Looks like it's caused by django-dynamic-fixtures, adding a couple of queries to get the object looks like made it to commit the insert queries.
class GoCouponsTestCaseMixin(object):
categories = []
stores = []
coupons = []
offers = []
def setUp(self):
self.categories.append(G(Category))
self.stores.append(G(Store, is_active=True))
# manually querying the objects fixed it
store = Store.objects.first()
category = Category.objects.first()
# make sure we generate enough coupons for page 2
for i in range(1, settings.COUPON_PAGE_SIZE + 10):
coupon = G(Coupon, title='free', store=store, is_active=True)
CouponCategory.objects.create(coupon=coupon, category=category)
Offer.objects.create(start=timezone.now() + timedelta(days=-10), expire=timezone.now() + timedelta(days=10), coupon=coupon)
self.coupons.append(coupon)
I have a couple of simple objects that have a many-to-many relationship. Django has joined them using obj1_obj2 table and it looks like this in mysql;
id | person_id | nationality_id
-----------------------------------
1 | 1 | 1
2 | 1 | 2
Now when I save obj1 (which shows obj2 in as Multi-select in its form) the ids in the obj1_obj2 table increase even thow I have not changed them. For example I change a basic character field for obj1 on its form and save it and the the data in the joining table appears to be deleted and re-saved giving the entries new ids.
In fact I don't have to change anything all I have to do is save the form and the same thing happens.
All I am doing in the view is form.save(), nothing special. Is that the normal way that it works?
EDIT: Added Models, Views, Forms
class Person(models.Model):
name = models.CharField()
birthdate = models.CharField()
nationality = models.ManyToMany(Nationality)
class Employee(Person):
employeeNum = models.CharField()
class FamilyMember(Person):
employee = models.ForeignKey(Employee)
relationship = models.CharField()
class Nationality(models.Model):
abbrev = models.CharField()
country = models.CharField()
class FamilyMemberDetailsForm(forms.ModelForm):
class Meta:
model = FamilyMemeber
exclude = ['employee']
def editFamilyMember(request, familyMember_id):
familyMember = get_object_404(FamilMember, familyMember_id)
if request.method == 'POST':
form = FamilyMemberDetailsForm(request.POST, instance=familyMember)
if form.is_valid():
form.save()
else:
form = FamilyMemberDetailsForm(instance=familyMember)
return render_to_response(editForm.html, {'form':form},
context_instance(RequestContext(request))
This is a cut down version of the models, but the same thing happens for saving an employee or familyMember. The FamilyMember I have shown because it is as simple as this I create the modelForm and then make changes and then save it. For the employee I do some more manipulation in the init of Form for the Nationality, mainly for presentation, and at first I thought it was this manipulation that was causing it, but as I said the same thing happens with the FamilyMember where I do nothing except save.
The Nationality is presented on the form as a multiselect box with a list and the user can select 1 or more from the list. If I just present the populated form and then save it without changing anything the id for the many-to-many table entry changes.
I have changed the example table titles also.
Thanks,
Andrew
Yes, the deletion of any existing rows in appname_obj1_obj2 is expected behavior when saving a form for an object that has a ManyToManyField.
You can see the clear() before the add(**values) in ReverseManyRelatedObjectsDescriptor and ManyRelatedObjectsDescriptor in django/db/models/fields/related.py.
Pop open a shell and take a look at the queries yourself. Something like this should show you the DELETE before the INSERT in the raw sql.
from django.db import connection
fm = FamilyMember.objects.get(pk=1)
form = FamilyMemberDetailsForm(instance=fm)
data = form.initial
data['name'] = "z%s" % data['name']
form = FamilyMemberDetailsForm(data, instance=fm)
connection.queries = [] # clearing to limit the queries you have to look at
form.save()
for q in connection.queries:
print("%s\n" % q['sql'])
I've got the flowing two models:
class Item(models.Model):
Name = models.CharField(max_length = 32)
class Profile(models.Model):
user = models.ForeignKey(User, unique = True)
ItemList = models.ManyToManyField(Item, related_name = "user_itemlist")
For Item X I want to get a list of Item objects present in ItemList for all Profile objects that contain X in ItemList, sorted by how many times each object appears.
The best I can do so far is:
Item.objects.filter(user_itemlist__in = User.objects.filter(profile__ItemList = X))
and this returns the list of all Item objects I need, with duplicates (if Item Z is present in ItemList for 10 Profile objects it will appear 10 times in the query result).
How can I sort the result of the above query by the number of times each object appears in the result and remove duplicates? Is there any "django" way to do that?
profiles = Profile.objects.filter(profile__ItemList=X)
Item.objects.filter(
user_itemlist__in=profiles
).annotate(itemcount=Count('id')).order_by('-itemcount')
if you're using django 1.0+ you can do this:
from django.db.models import Count
# note that 'profile' is an instance of Profile, not the model itself
sorted_items = profile.ItemList.annotate(itemcount=Count('name'))
sorted_items = sorted_items.order_by('-itemcount')
#number of occurences of top item
sorted_items[0].itemcount