[Python] Adding Markers to OpenStreetMap's Django/Python

Discussão em 'Python' iniciado por Stack, Março 11, 2025.

  1. Stack

    Stack Membro Participativo

    I'm having issues with leaflet, and OpenStreetMap I cannot get a marker to be added for each job available. it just shows up as a blank map. Debugging shows that the information is being sent correctly but the map is not update. Here is the debug info. The list view works perfectly. and the map shows a correct marker when clicking on job from list view.

    (0.001) SELECT "users_job"."id", "users_job"."title", "users_job"."description", "users_job"."city", "users_job"."state", "users_job"."zip", "users_job"."latitude", "users_job"."longitude" FROM "users_job"; args=(); alias=default
    Jobs List: [{'id': 1, 'title': 'test job', 'description': 'this is a test', 'city': '*redacted*', 'state': '*redacted*', 'zip': '*redacted*', 'latitude': *redacted*, 'longitude': *redacted*}, {'id': 2, 'title': 'testjob2', 'description': 'This is a test', 'city': '*redacted*', 'state': '*redacted*', 'zip': '*redacted*', 'latitude': *redacted*, 'longitude': *redacted*}, {'id': 3, 'title': 'test job json', 'description': 'json test', 'city': '*redacted*', 'state': '*redacted*', 'zip': '*redacted*', 'latitude': *redacted*, 'longitude': *redacted*}, {'id': 4, 'title': 'jsontest2', 'description': 'asdofmasodfm', 'city': '*redacted*', 'state': '*redacted*', 'zip': '*redacted*', 'latitude': *redacted*, 'longitude': *redacted*}]
    (0.002) SELECT "django_session"."session_key", "django_session"."session_data", "django_session"."expire_date" FROM "django_session" WHERE ("django_session"."expire_date" > '2025-03-11T01:18:30.939183+00:00'::timestamptz AND "django_session"."session_key" = '*redacted*') LIMIT 21; args=(datetime.datetime(2025, 3, 11, 1, 18, 30, 939183, tzinfo=datetime.timezone.utc), '*redacted*'); alias=default
    (0.002) SELECT "users_user"."id", "users_user"."password", "users_user"."last_login", "users_user"."is_superuser", "users_user"."username", "users_user"."is_staff", "users_user"."is_active", "users_user"."date_joined", "users_user"."email", "users_user"."phone_number", "users_user"."address", "users_user"."city", "users_user"."state", "users_user"."zip", "users_user"."latitude", "users_user"."longitude", "users_user"."avatar", "users_user"."user_type", "users_user"."first_name", "users_user"."last_name" FROM "users_user" WHERE "users_user"."id" = 2 LIMIT 21; args=(2,); alias=default
    "GET / HTTP/1.1" 200 8512


    {% extends "users/base.html" %}
    {% block title %} Home Page {% endblock title %}
    {% block content %}
    <div class="container py-5">

    <!-- Toggle Button -->
    <div class="btn-group" role="group" aria-label="View Toggle">
    <button id="map-view-btn" type="button" class="btn btn-primary">Map View</button>
    <button id="list-view-btn" type="button" class="btn btn-secondary">List View</button>
    </div>

    <!-- Map View -->
    <div id="map-view" style="height: 400px; width: 100%; display: none;">
    <div id="map" style="height: 100%; width: 100%;"></div>
    </div>

    <div class="container py-5">
    <div id="debug-info" style="display: none; border: 1px solid #ccc; padding: 10px; margin-top: 20px;">
    <h5>Debug Information</h5>
    <pre id="debug-content"></pre>
    </div>
    </div>

    <!-- List View -->
    <div id="list-view" style="display: none;">
    <ul class="list-group">
    {% for job in jobs %}
    {% if job.id %}
    <li class="list-group-item">
    <h5><a href="{% url 'job_detail' job.id %}">{{ job.title }}</a></h5>
    </li>
    {% else %}
    <li class="list-group-item">Invalid job data: {{ job|safe }}</li> <!-- Debugging statement -->
    {% endif %}
    {% empty %}
    <li class="list-group-item">No jobs available</li>
    {% endfor %}
    </ul>
    </div>

    <script id="job-data" type="application/json">
    {{ jobs|json_script:"job-data" }}
    </script>

    <!-- Hidden element to store user's location -->


    <script>
    document.addEventListener('DOMContentLoaded', function() {
    var mapViewBtn = document.getElementById('map-view-btn');
    var listViewBtn = document.getElementById('list-view-btn');
    var mapView = document.getElementById('map-view');
    var listView = document.getElementById('list-view');
    var debugInfo = document.getElementById('debug-info');
    var debugContent = document.getElementById('debug-content');

    // Show map view by default
    mapView.style.display = 'block';

    mapViewBtn.addEventListener('click', function() {
    mapView.style.display = 'block';
    listView.style.display = 'none';
    mapViewBtn.classList.add('btn-primary');
    mapViewBtn.classList.remove('btn-secondary');
    listViewBtn.classList.add('btn-secondary');
    listViewBtn.classList.remove('btn-primary');
    });

    listViewBtn.addEventListener('click', function() {
    mapView.style.display = 'none';
    listView.style.display = 'block';
    mapViewBtn.classList.add('btn-secondary');
    mapViewBtn.classList.remove('btn-primary');
    listViewBtn.classList.add('btn-primary');
    listViewBtn.classList.remove('btn-secondary');
    });

    // Set initial location to the geographical center of the United States
    var initialLocation = [37.0902, -95.7129]; // Latitude and Longitude of the geographical center of the US
    var initialZoom = 4; // Zoom level to show the entire US

    var map = L.map('map').setView(initialLocation, initialZoom);

    L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
    attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
    }).addTo(map);

    var jobs = JSON.parse(document.getElementById('job-data').textContent); // Ensure jobs data is passed as a safe JSON object

    console.log("Jobs data:", jobs); // Debugging statement to log jobs data

    if (jobs.length === 0) {
    console.warn("No jobs available");
    }

    jobs.forEach(function(job) {
    console.log("Processing job:", job); // Debugging statement to log each job
    var jobLocation = [job.latitude, job.longitude];
    console.log("Job location:", jobLocation); // Debugging statement to log job location
    if (job.latitude !== 0 && job.longitude !== 0) { // Ensure valid coordinates
    L.marker(jobLocation).addTo(map)
    .bindPopup('<b>' + job.title + '</b><br>' + job.zip);
    } else {
    console.warn("Invalid coordinates for job:", job); // Warn about invalid coordinates
    }
    });

    // Display debug information in the container
    debugContent.textContent = 'Jobs data: ' + JSON.stringify(jobs, null, 2);
    debugInfo.style.display = 'block';
    });
    </script>
    {% endblock content %}


    Here is the Job form

    # Job Form
    class JobForm(forms.ModelForm):
    title = forms.CharField(max_length=100, widget=forms.TextInput(attrs={'class': 'form-control'}))
    description = forms.CharField(widget=forms.Textarea(attrs={'class': 'form-control'}))
    address = forms.CharField(max_length=300, widget=forms.TextInput(attrs={'class': 'form-control'}))
    city = forms.CharField(max_length=100, widget=forms.TextInput(attrs={'class': 'form-control'}))
    state = forms.CharField(max_length=25, widget=forms.Select(choices=STATE_CHOICES, attrs={'class': 'form-control state-select'})) # Add custom class
    zip = forms.CharField(max_length=12, widget=forms.TextInput(attrs={'class': 'form-control'}))
    budget = forms.DecimalField(widget=forms.NumberInput(attrs={'class': 'form-control'}))
    deadline = forms.DateField(widget=forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}))
    document = forms.FileField(widget=forms.ClearableFileInput(attrs={'class': 'form-control'}), required=False)
    image = forms.ImageField(widget=forms.ClearableFileInput(attrs={'class': 'form-control'}), required=False)

    class Meta:
    model = Job
    fields = ['title', 'description', 'address', 'city', 'state', 'zip', 'budget', 'deadline', 'document', 'image']

    def save(self, commit=True):
    job = super().save(commit=False)
    if job.zip:
    job.latitude, job.longitude = job.get_lat_lng_from_zip(job.zip)
    if commit:
    job.save()
    return job


    Here is the job model

    # Job Model
    class Job(models.Model):
    id = models.BigAutoField(primary_key=True)
    customer = models.ForeignKey(User, on_delete=models.CASCADE)
    title = models.CharField(max_length=255)
    description = models.TextField(max_length=1000, default='No description provided')
    address = models.CharField(max_length=255, blank=True, null=True)
    city = models.CharField(max_length=100, blank=True, null=True)
    state = models.CharField(max_length=25, blank=True, null=True) # Add the state field
    zip = models.CharField(max_length=10, default='11111')
    latitude = models.FloatField(default=0)
    longitude = models.FloatField(default=0)
    budget = models.DecimalField(max_digits=12, decimal_places=2)
    deadline = models.DateField(default='2021-12-31')
    created_at = models.DateTimeField(auto_now_add=True)
    document = models.FileField(upload_to='job_documents/', blank=True, null=True)
    image = models.ImageField(upload_to='job_images/', blank=True, null=True)

    def save(self, *args, **kwargs):
    if self.zip:
    lat, lng = self.get_lat_lng_from_zip(self.zip)
    if lat is not None and lng is not None:
    self.latitude = lat
    self.longitude = lng
    else:
    logger.error(f"Failed to get latitude and longitude for zip code: {self.zip}")
    if self.city and not self.state:
    self.state, lat, lng = self.get_state_and_coords_from_city(self.city, self.zip)
    if lat is not None and lng is not None:
    self.latitude = lat
    self.longitude = lng
    super().save(*args, **kwargs)

    def get_lat_lng_from_zip(self, zip_code):
    url = f'https://nominatim.openstreetmap.org/search?postalcode={zip_code}&format=json&countrycodes=us'
    headers = {
    'User-Agent': 'ConstructionConnect/1.0 (jonnytombstone@gmail.com)' # Replace with your app name and email
    }
    try:
    response = requests.get(url, headers=headers)
    response.raise_for_status() # Raise an HTTPError for bad responses
    data = response.json()
    logger.debug(f"Response data for zip code {zip_code}: {data}") # Log the response data
    if data:
    location = data[0]
    lat = float(location.get('lat', 0))
    lon = float(location.get('lon', 0))
    logger.debug(f"Extracted lat: {lat}, lon: {lon} for zip code {zip_code}")
    return lat, lon
    except requests.RequestException as e:
    logger.error(f"Error fetching latitude and longitude for zip code {zip_code}: {e}")
    return None, None


    Here is the Job View


    def home(request):
    jobs = Job.objects.all()
    jobs_list = list(jobs.values('id', 'title', 'description', 'city', 'state', 'zip', 'latitude', 'longitude'))

    # Log the jobs_list data for debugging
    logger.debug('Jobs List: %s', jobs_list)

    # Job Views
    @login_required
    def job_detail(request, job_id):
    job = get_object_or_404(Job, id=job_id)
    comments = job.comments.all()

    if request.method == 'POST':
    comment_form = CommentForm(request.POST)
    if comment_form.is_valid():
    comment = comment_form.save(commit=False)
    comment.job = job
    comment.author = request.user
    comment.save()
    return redirect('job_detail', job_id=job.id)
    else:
    comment_form = CommentForm()

    context = {
    'job': job,
    'comments': comments,
    'comment_form': comment_form,
    }
    return render(request, 'users/job_detail.html', context)

    Continue reading...

Compartilhe esta Página