How should I model this out? - django

I am a bit stuck on how I should model this out.
Here is what I have:
I have a model called Location. In this model I have postal code, city, region, longitude, and latitude. This data is pre-populated with all of Canada's stuff. You can imagine this table is quite large.
This is what I would like to achieve by stuck on how to model this:
I would like to create a second model called Item. Each one of these items will need to be tied to a location from the said above model. The user-story would be as follows:
User adds an item: I already know their postal code and city based on their cookie that I set.
User submits the form with their item: this is where I am confused as to how to model this data so that the item gets saved in the proper location.
I figured a FK would be the way to go but that is waaaaay to inefficient for a number of obvious reasons (huge list, and requires user input but I already know their location before saving). So, since I already know their location based on their cookie, should create a new field in the Item model called location and just save the postal code in this model? If I did this I guess I would have to query the location model for that location to pull in proper info. I am not sure what the best to go about this is, please help.

If you already know the user's location, and they're just entering an item, then the Item model should have a foreign key to Location, but you don't prompt for it on the form. Instead, fill in the Location before you save the item.
If you're using a ModelForm, then you'll want to exclude your location field so that it isn't displayed. You'll also want to set commit=False so that you can fill in the location yourself before saving the form data to the Item table.

Related

User generated item multiple choice field Django

I am looking for a way to have a multiple choice field populated with choices made by a user. For example, they could have the following 3 entries: Yes, No, Unsure. I want a way to be translate this to a model.
I understand this can be done with pre-defined options using a CharField, or ChoiceField, but I haven't seen anything with "dynamic" data, such as user-generated data.
I think you shouldn't use choice fields in this case, because everytime a user creates a new option, you'll have to run a new migration.
Maybe you can create a UserOption model and create a new obj everytime a user creates a new option. Then fetch all the options the user has created when he needs to choose between them.
You can't apply user choices to a DB table. However, you could store a user's choices somewhere, such as a User's Profile, and use them in a dynamically constructed form with a ChoiceField to constrain what he can put into a particular database column / model field.
Could be a PITA if he decides to delete a choice and then wants to edit the (now invalid) data in one of his records.

Django - set model's `CharField` primary key from processed `ImageField` data

This is maybe a poor way to ask this question, as I haven't yet tried anything since I'm not sure if it's even possible without a bunch of custom JS added to the admin.
Given a model such as:
class MyModel(models.Model):
sku = models.CharField('SKU', max_length=20, primary_key=True)
bar_code = models.ImageField(upload_to='images/barcodes')
I want the user to select an image which will be a photo of a product's barcode. The image then needs to be processed to scan for the barcode (I'm using pyzbar) and this value should be saved to the primary key field sku.
Since I can't save the model without a primary key, and I need to upload the image field to scan the barcode to discover the value to be used for the primary key, I'm thinking that the only way to do this would be to use some client side JS in the admin to upload the image to a temp location using a DRF endpoint (or similar), read the barcode and return that value to the client which could then set the value of sku with some basic javascript. Then the model can be saved and image uploaded (a second time).
Is there a more straightforward way to do this in Django without adding my own client side JS to the admin and having to upload the photo twice?
Aside from the primary key, which may complicate things - you can extend ImageField and see how it populates its width and height columns, then do the same for the pyzbar generated barcode. See the update_dimension_fields for inspriation:
Update field's width and height fields, if defined.
This method is hooked up to model's post_init signal to update
dimensions after instantiating a model instance. However, dimensions
won't be updated if the dimensions fields are already populated. This
avoids unnecessary recalculation when loading an object from the
database.
Dimensions can be forced to update with force=True, which is how
ImageFileDescriptor.set calls this method.
You would add a method to do the work for pyzbar and then connect the signal in the same way.

Is it possible to improve the process of instance creation/deletion in Django using querysets?

So I have a list of unique pupils (pupil is the primary_key in an LDAP database, each with an associated teacher, which can be the same for several pupils.
There is a box in an edit form for each teacher's pupils, where a user can add/remove an pupil, and then the database is updated according using the below function. My current function is as follows. (teacher is the teacher associated with the edit page form, and updated_list is a list of the pupils' names what has been submitted and passed to this function)
def update_pupils(teacher, updated_list):
old_pupils = Pupil.objects.filter(teacher=teacher)
for pupils in old_pupils:
if pupil.name not in updated_list:
pupil.delete()
else:
updated_list.remove(pupil.name)
for pupil in updated_list:
if not Pupil.objects.filter(name=name):
new_pupil = pupil(name=name, teacher=teacher)
new_pupil.save()
As you can see the function basically finds what was the old pupil list for the teacher, looks at those and if an instance is not in our new updated_list, deletes it from the database. We then remove those deleted from the updated_list (or at least their names)...meaning the ones left are the newly created ones, which we then iterate over and save.
Now ideally, I would like to access the database as infrequently as possible if that makes sense. So can I do any of the following?
In the initial iteration, can I simply mark those pupils up for deletion and potentially do the deleting and saving together, at a later date? I know I can bulk delete items but can I somehow mark those which I want to delete, without having to access the database which I know can be expensive if the number of deletions is going to be high...and then delete a lot at once?
In the second iteration, is it possible to create the various instances and then save them all in one go? Again, I see in Django 1.4 that you can use bulk_create but then how do you save these? Plus, I'm actually using Django 1.3 :(...
I am kinda assuming that the above steps would actually help with the performance of the function?...But please let me know if that's not the case.
I have of course been reading this https://docs.djangoproject.com/en/1.3/ref/models/querysets/ So I have a list of unique items, each with an associated email address, which can be the same for several items.
First, in this line
if not Pupil.objects.filter(name=name):
It looks like the name variable is undefined no ?
Then here is a shortcut for your code I think:
def update_pupils(teacher, updated_list):
# Step 1 : delete
Pupil.objects.filter(teacher=teacher).exclude(name__in=updated_list).delete() # delete all the not updated objects for this teacher
# Step 2 : update
# either
for name in updated_list:
Pupil.objects.update_or_create(name=name, defaults={teacher:teacher}) # for updated objects, if an object of this name exists, update its teacher, else create a new object with the name from updated_list and the input teacher
# or (but I'm not sure this one will work)
Pupil.objects.update_or_create(name__in=updated_list, defaults={teacher:teacher})
Another solution, if your Pupil object only has those 2 attributes and isn't referenced by a foreign key in another relation, is to delete all the "Pupil" instances of this teacher, and then use a bulk_create.. It allows only 2 access to the DB, but it's ugly
EDIT: in first loop, pupil also is undefined

Django Model Table temporary data vs. permanent data

I am writing a trip planner, and I have users. For the purposes of this question, lets assume my models are as simple as having a "Trip" model and having a "UserProfile" model.
There is a functionality of the site that allows to search for routes (via external APIs), and then dynamically assembles those into "trips", which we then display. A new search deletes all the old "trips" and figures out new ones.
My problem is this: I want to save some of these trips to the user profile. If the user selects a trip, I want it to be permanently associated with that profile. Currently I have a ManyToMany field for Trips in my UserProfile, but when the trips are "cleaned/flushed", all trips are deleted, and that association is useless. I need a user to be able to go back a month later and see that trip.
I'm looking for an easy way to duplicate that trip data, or make it static once I add it to a profile . .. I don't quite know where to start. Currently, the way it is configured is there is a trips_profile datatable that has a foreign key to the "trips" table . . . which would be fine if we weren't deleting/flushing the trips table all the time.
Help appreciated.
It's hard to say exactly without your models, but given the following layout:
class UserProfile(models.Model):
trips = models.ManyToManyField(Trip)
You can clear out useless Trips by doing:
Trip.objects.filter(userprofile__isnull=True).delete()
Which will only delete Trips not assigned to a UserProfile.
However, given the following layout:
class Trip(models.Model):
users = models.ManyToManyField(User)
You could kill the useless trips with:
Trip.objects.filter(users__isnull=True).delete()
The second method has the side benefit of not requiring any changes to UserProfile or even a UserProfile at all, since you can then just get a Users trips with:
some_user.trip_set.all()

Django admin store dynamic formset added with ajax

I'm currently implementing a solution using django admin, it allows users to define in the db a product, and then custom attributes and details, more details may be aggregated by a common attribute, this allows me to query with ajax a custom view that returns some JSON data to build automagically the form fields that I need directly in the same formset view (manipulating the DOM).
The current DB design follows this schema:
Catalog(name, description, photo)
Product(rel_catalog, name, base_price, photo, manufacturer_email)
ProductDetail(rel_product, rel_attribute, percentage_price, fixed_price)
ProductAttribute(rel_product, name, description)
As you may see I have a catalog, where there can be more products, a lot of details per product, aggregated by attributes. Then I simple show by default the Catalog, then the select with all available products for that catalog, then, choosing the right Product, I obtain the complete form (each row has a label with ProductAttribute.name and a select with related ProductDetail).
All works pretty dam good, but I also need to store this references in the DB when someone completes the form (making an order with choosen products). This forms are displayed as StackedInline (the ModelAdmin is for the Order).
I don't know how many options there may be per product so I was thinking to use this design to track orders:
Order(customer, status, notes, tot_price, inserted_by)
OrderItem(rel_order, catalog, product, unit_price)
But I don't know how to store the dynamic added inputs...
I was thiking to implement OrderItemProperty(rel_orderitem, rel_productdetail, rel_productattribute) to store each single input... but how do I loop over this unknown fields?
Maybe do you suggest a better design?
If you need more code just ask for it and I'll reply with a pastebin link.
Thankyou.
Finally I got a working solution,
I've created a custom view, overriding the default "add/" view, this way I can customize whatever I want to and I can read the POST data handling each validation, putting then the data in the right model.