Storing restaurant categories in GeoDjango project - django

I am making a geo django backend for an iPhone app. The iphone app sends users current location to the backend, which returns nearby restaurants (something similar to Foursquare and Yelp.)
I am not entirely sure how to store the cuisine for the restaurants. I need an option where the user can look up/select a specific cuisine for example only Chinese food. Should I create a seperate model for restaurant cuisine and have one to many relationship with the restaurants ? or should I use boolean value like this:
models.BooleanField(default=False)
Here is the code for my Model:
from django.db import models
from django.contrib.gis.db import models as gis_models
from django.contrib.gis import geos
from django.db import models
# Create your models here.
class Restaurant(models.Model):
name = models.CharField(max_length = 100)
address = models.CharField(max_length = 150)
phone = models.CharField(max_length = 12)
cuisine = models.CharField(max_length = 50)
eatingOptions = models.CharField(max_length = 50)
location = gis_models.PointField(u'Latitude/Longitude', geography=True, blank=True, null=True)
# Query Manager
gis = gis_models.GeoManager()
objects = models.Manager()
def __unicode__(self):
return self.name

Only you and your requirements can answer that.
If you create a separate model and have a relationship it will be more flexible, you can have different cuisines without changing the model. Best option if your database will have multiple types of cuisine.
If you choose to use a BooleanField like is_chinese then it will work only for chinese cuisine. This is the best option if you only care for one type of cuisine.
Don't worry if you make a bad judgement when developing (at least on an early stage), django has your back.
Hope that helps.

Related

Django models for astra datastax db

I have developed a website on Django. Initially, I used Django's default Database which is Sqlite3. Now I want to use Astra Datastax DB which is Cassandra. I am not able to convert Django.dB - models into Cassandra.cqlengine - columns function.
I have searched on the Internet and didn't find appropriate documents which could help me.
from django.db import models
from django.contrib.auth import get_user_model
from datetime import datetime
import uuid
User = get_user_model()
class Profile(models.Model):
"""docstring for Profile."""
usr: str = models.ForeignKey(User, on_delete=models.CASCADE)
id_usr: int = models.IntegerField()
Fname:str = models.TextField(blank=True,null=True)
Mname:str = models.TextField(blank=True,null=True)
Lname:str = models.TextField(blank=True,null=True)
Fhone:int = models.IntegerField(blank=True,null=True)
bio: str = models.TextField(blank=True)
img_profile = models.ImageField(
upload_to='ProfileIMG', default="blankprofile.png")
location: str = models.CharField(max_length=250)
def __str__(self):
return self.usr.username
class Post(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, unique=True)
user: str = models.CharField(max_length=100)
image = models.ImageField(upload_to="img_posts")
caption: str = models.TextField(max_length=250)
created_at = models.DateTimeField(default=datetime.now)
Likes: int = models.IntegerField(default=0)
def __str__(self):
return self.user
class LikePost(models.Model):
postid: str = models.CharField(max_length=100)
username: str = models.CharField(max_length=100)
def __str__(self):
return self.username
class Followers(models.Model):
follower: str = models.CharField(max_length=100)
user: str = models.CharField(max_length=100)
def __str__(self):
return self.user
Specially, I want to convert this into Cassandra language.
img_profile = models.ImageField( upload_to='ProfileIMG', default="blankprofile.png")
The documentation you want to consult is here: https://docs.datastax.com/en/developer/python-driver/3.25/api/cassandra/cqlengine/columns/
These are the available columns for DjangoCassandraModel, which is what you would use instead of django.db.models to get a model backed by Cassandra. You can see a basic example of connecting to DataStax Astra with django_cassandra_engine here: https://github.com/DataStax-Examples/django-cassandra-blog
As for the ImageField, I am not sure of the Django internals here, but I believe it stores a path to the file in the database after putting it on disk at the location specified ("img_posts" in your example).
You could do the same for a Cassandra backed model, or use the Blob column type to store the image data itself. There are a number of articles and examples of doing this out there.
To add to the above answer, the django_cassandra_engine package does not offer anything with the same level of automation as the ImageField found in Django's models (i.e. storing the uploaded image on local disk and saving the string path to the database, all from the field definition in the model).
What you would do is to work at a slightly lower abstraction level with an explicit (Django, pure) form. This would allow you to manually handle the file upload as outlined here: https://docs.djangoproject.com/en/4.1/ref/forms/fields/#filefield .
Once you have saved the file and have the string path to it, you can create ann istance of the corresponding Model and manually save it -- all in the appopriate view function.
As a side note, your original (sqlite-backed) code makes use of foreign keys and "on delete cascade" provision for removing related rows from other tables. This cannot be transported as is to a Cassandra storage, since the database, by itself, does not support the concept of relational integrity. You would have to decide how to handle these deletes and act on them explicitly in your code.

Best practices for GeoDjango Models

I have a classic GeoDjango model
from django.contrib.gis.db import models
class Location(models.Model):
vessel = models.ForeignKey(Vessel, on_delete=models.CASCADE)
timestamp = models.DateTimeField(auto_now_add=True, blank=True)
point = models.PointField()
However usage seems quite clumsy;
>>> foo = somevessel.location_set.create(point=Point(5, 23))
>>> foo.point.x
5.0
I still want to store the location as a point but would prefer to interact with the model with more native looking code, something like
>>> foo = somevessel.location_set.create(latitude=5, longitude=12)
>>> foo.latitude
5.0
Is this against best practices? And is there a simple way to achieve this in Django?
I think that implicitly formalizing your point like this, i.e. with latitude and longitude FloatFields, will not allow you to fully benefit from spatial lookup capabilities. If not a "bad practice", this is likely to be a no-starter.
I still want to store the location as a point but would prefer to interact with the model with more native looking code,
To interact with the model in a more native looking way, I would define properties in my model class which would actually return latitude and/or longitude, doing
from django.contrib.gis.db import models
class Location(models.Model):
vessel = models.ForeignKey(Vessel, on_delete=models.CASCADE)
timestamp = models.DateTimeField(auto_now_add=True, blank=True)
point = models.PointField()
#property
def latitude(self):
return self.point.x
#property
def longitude(self):
return self.point.y
Allowing you to do
>>> foo = somevessel.location_set.create(point=Point(5, 23))
>>> foo.latitude
5.0

How to convert django ManyToManyField into Django-nonrel Field?

I build an app in django, but since I found out that google app engine doesn't support Django out of the box (free,cloud sql can't be used for free right?).
I decided to move to Django-nonrel, so there are few datebase Field that need converting, and I don't know how:
class Cate(models.Model):
name = models.CharField(max_length = 100)
description = models.TextField()
create_by = models.ForeignKey(User)
create_date = models.DateTimeField('cate created date')
def __unicode__(self):
return self.name
class Product(models.Model):
product_name = models.CharField(max_length = 200)
owner = models.ForeignKey(User)
cate = models.ManyToManyField(Cate)
timestamp = models.DateTimeField('product added date')
view = models.IntegerField(default = 0)
def __unicode__(self):
return self.product_name
here is the user_profile model which extends from user model
class UserProfile(models.Model):
user = models.OneToOneField(User)
cates = models.ManyToManyField('shop.Cate')
the Cate model is created by admin, UserProfile can have many cates, and same cate can belong to many users, same as product.
please help to construct these models and maybe some tips on how to use Django-nonrel
I am really new to database
There's two ways to do this. The cheaper version is to use ListFields
from djangotoolbox.fields import ListField
class UserProfile(models.Model):
user = models.OneToOneField(User)
cates = ListField(models.ForeignKey(shop.Cate))
The ListField simply stores a list of Cate ids. There's some important limitations to this.
Your entity is limited to 1MB, so this limits the number of entities in your list. In this case, it'll still be a fairly large number, especially since there's nothing else in your entity.
You can do dataastore queries against the cates field if it's indexed. However, each entity has a limit of 5000 indexes. You'll use one for the user attribute, so in this case, your cates list will be limited to have 5000 entries. I haven't hit this before so I don't know how it would fail, I presume you'd get an exception on writing your entity.
The more expensive option is to use an intermediate mapping entity. This gives you unlimited relations for the extra expense of creating/querying the mapping entities.
class UserCateMapping(models.Model)
user = models.ForeignKey(UserProfile)
cate = models.ForeignKey(Cate)
In this case, you'll need to create a new entity for each relation, and query for the UserCateMapping entities before fetching the actual Cate or UserProfile entity you actually want to use. It's going to be more costly than the first option, but you'll have unlimited mappings.

DRY django models, creating a list of objects

I have some model for a user profile and I want to be able to store several types of information but with some deferences (like a home or work phone number) but I don't want to use a ForeignKey relation ...how would I do that?
something like:
class Profile(models.Model):
phone = ? list of some kind ?
class Phone(???):
TYPE_CHOICES = (
('H', 'Home'),
('W', 'Work'),
('F', 'Fax'),
)
type = models.CharField(max_length = 1, choices = TYPE_CHOICES)
number = models.CharField(max_length = 16)
private = models.BooleanField()
Thank you!
Edit: I didn't want to use a foreign key just because I originally wanted all information relating to a user to show up on the profile admin page. but... meh... that's not too critical
Why don't you want to use a foreign key? If you want to have multiple phone numbers, that's the way you need/must do it.
It's easy to work with Django and foreign keys, and you can easily add an inline model formset into the admin page to create/edit a user profile with plenty of phone numbers.
Your models should look like this:
class Profile(models.Model):
name = models.CharField(max_length=40, verbose_name="User name")
class Phone(models.Model):
TYPE_CHOICES = (
('H', 'Home'),
('W', 'Work'),
('F', 'Fax'),
)
profile = models.ForeignKey(Profile)
type = models.CharField(max_length = 1, choices = TYPE_CHOICES)
number = models.CharField(max_length = 16)
private = models.BooleanField()
Then, you could use something like this to easily add/edit multiple phone numbers per profile in one admin page.
In your example, you should do something like this (inside admin.py file, in your django app):
class PhoneInline(admin.TabularInline):
model = Phone
class ProfileAdmin(admin.ModelAdmin):
inlines = [
PhoneInline,
]
admin.site.register(Profile, ProfileAdmin)
Now, you can go to the admin interface and try to add a new profile. You will see that you can add multiple phones per profile. I hope it helps you...
Finally, i'll recommend you to take a tour on django's tutorials. You will understand a lot of things and you will get a good idea of how to work with it.

Django - "last_modified" or "auto_now_add" for an App (or more than one Model?)

I know Django has a feature of last_modified field (models.DateTimeField(auto_now_add=True)
)..
but let's say I have a certain App, and I want to know when was the last change for any of its Model (I don't really care which model was changed, I just want to know when was the latest change for this app..)
do I really have to write a last_modified field for each model (I have 9 of them for the moment...), and then check for each of them which is the latest?
any help will be appreciated :)
Thanks
You could create a base class that defines the last_modified field...
class YourBaseClassName(models.Model):
last_modified = models.DateTimeField(auto_now=True)
and then inherit from that
class AnotherClass(YourBaseClassName):
another_field = models.CharField(max_length=50)
In The End I made a table for constants for my app (actually I had it before for use of other things).
so the Table looks like this:
from django.db import models
from django.db.models.signals import post_save
class Constant(models.Model):
name = models.CharField(max_length=50)
value = models.CharField(max_length=50)
and added a consant named "version_date".
Than, I added this code to the bottom of my models.py, to track all changes in all the models in the app.
myapp = models.get_app('myapp')
models2track = models.get_models(myapp)
def update_version(sender, **kwargs):
for model in models2track:
post_save.disconnect(update_version, sender=model, dispatch_uid="some_uid"+model._meta.db_table)
version_date = Constant.objects.get_or_create(id=1,name="version date")[0]
version_date.value = str(int(time.time()))
version_date.save()
for model in models2track:
post_save.connect(update_version, sender=model, dispatch_uid="some_uid"+model._meta.db_table)
for model in models2track:
post_save.connect(update_version, sender=model, dispatch_uid="some_uid"+model._meta.db_table)
This way, I don't need to change my DB Schema.. only need to add the code mentioned.
thanks all